Search code examples
pythongarbage-collection

Does python garbage collector collects objects with cyclic allocations like below?


Will variable "a" be garbage collected by python garbage collector?

a = [1,2,3]
b = [a,a]
a.append(b)

If yes, then what happens if we change value of a dynamically? And how does "b" works if the a has been garbage collected? As per my understanding, the reference to a is lost. Does "b" keeps a new copy itself while the initialisation?

I am trying to understand the garbage collection mechanism in python. I read in a blog post that in above code, "a" will get collected by the garbage collector as it is a cycle detection case.


Solution

  • After a = [1,2,3]; b = [a, a], the references look like this:

      a -----------------------> 
               +--------------->   [1, 2, 3]
               |  +------------>
               |  |
      b --> [  *, *  ]
    

    Namely, the first list has three references pointing two it: one held by the name a, the other two by the second list. The second list itself has one reference to it, held by b.

    After a.append(b), there is one new reference added to the first list, which points to the second list.

      a -----------------------> 
               +--------------->   [1, 2, 3, *]
               |  +------------>             |
               |  |                          |
      b --> [  *, *  ] <---------------------+
    

    Nothing is garbage-collected, because both lists have references. Even if we execute del a, nothing will be garbage-collected, because now memory looks like this:

               +--------------->   [1, 2, 3, *]
               |  +------------>             |
               |  |                          |
      b --> [  *, *  ] <---------------------+
    

    Both lists are reachable: the second via b, and the first list via the second.

    Now, if we do del b as well, now we have something like this:

               +--------------->   [1, 2, 3, *]
               |  +------------>             |
               |  |                          |
            [  *, *  ] <---------------------+
    

    Both lists have references to each other, but "we" have no references to either. Now the garbage collector would identify this unreachable reference cycle and collect both lists.