Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Preventing cyclic reference memory leaks in Perl

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?

like image 970
tjwrona1992 Avatar asked Aug 14 '15 13:08

tjwrona1992


1 Answers

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.

like image 72
Sobrique Avatar answered Oct 13 '22 09:10

Sobrique