11

I recently asked a question about overwriting objects and memory management in Perl. One of the answers I received notified me that I may have an issue with a script I recently wrote.

I have a script with some very complex data structures that have many parent->child / child->parent relationships. This also means that there are many objects that have cyclic references. According to this answer, cyclic references can "trick" Perl's reference counting mechanism and cause memory leaks if they are not dealt with properly.


Example of a cyclic reference:

       +-----------------------------------------------------+
       |                                                     |
       +-->+============+    +==========+                    |
           [ Reference ----->[ Blessed  ]                    |
$parent -->+============+    [ Hash     ]                    |
                             [          ]   +==========+     |
                             [ children --->[ Array    ]     |
                             [          ]   [          ]     |
                             +==========+   [ 0: ---------+  |
                                            [          ]  |  |
                                            +==========+  |  |
                                                          |  |
       +--------------------------------------------------+  |
       |                                                     |
       +-->+============+    +==========+                    |
           [ Reference ----->[ Blessed  ]                    |
$child --->+============+    [ Hash     ]                    |
                             [          ]                    |
                             [ parent: ----------------------+
                             [          ]
                             +==========+

(Disclaimer -- this is not my epic artwork -- Thanks @Ikegami for this sweet ASCII diagram!)

Problem: Each object has a reference to the other . . . this means that once $parent and $child go out of scope, Perl's reference counter still thinks that a reference to each object exists so the memory is never freed. You wind up with two objects in memory with no way to access the data of either of them!


My question is: What is the proper way to deal with cyclic references to ensure Perl handles its cleanup properly? How do you make sure Perl doesn't leave any pieces behind when all external references to a self-referential object are eliminated?

Community
  • 1
  • 1
tjwrona1992
  • 8,614
  • 8
  • 35
  • 98

1 Answers1

13

Scalar::Util and specifically the weaken function.

The lvalue $ref will be turned into a weak reference. This means that it will not hold a reference count on the object it references. Also when the reference count on that object reaches zero, the reference will be set to undef. This function mutates the lvalue passed as its argument and returns no value.

Set one - or both - of your references as "weak" and the daisy chain will unravel automagically when the anchors are destructed.

Sobrique
  • 52,974
  • 7
  • 60
  • 101
  • 2
    Cool I will try that out. I wish I knew about this about a month ago... I've got lots of references to weaken! – tjwrona1992 Aug 14 '15 at 13:22
  • Hmm there can still be some issues with this depending on how the objects are used... (see [here](http://stackoverflow.com/questions/32013133/can-using-scalarutils-weaken-cause-invalid-reference-problems)) But overall this does solve the primary problem of the memory leak so I have selected this answer. – tjwrona1992 Aug 17 '15 at 13:49