我最近问过question有关在Perl中覆盖对象和内存管理的问题。我收到的一个答案告诉我,我最近写的脚本可能有问题。
我有一个脚本,其中包含一些非常复杂的数据结构,这些数据结构有很多parent->child / child->parent
个关系。这也意味着有许多对象具有循环引用。根据{{3}},循环引用可以"技巧" Perl的引用计数机制,如果处理不当,会导致内存泄漏。
循环参考的示例:
+-----------------------------------------------------+
| |
+-->+============+ +==========+ |
[ Reference ----->[ Blessed ] |
$parent -->+============+ [ Hash ] |
[ ] +==========+ |
[ children --->[ Array ] |
[ ] [ ] |
+==========+ [ 0: ---------+ |
[ ] | |
+==========+ | |
| |
+--------------------------------------------------+ |
| |
+-->+============+ +==========+ |
[ Reference ----->[ Blessed ] |
$child --->+============+ [ Hash ] |
[ ] |
[ parent: ----------------------+
[ ]
+==========+
(免责声明 - 这不是我的史诗作品 - 感谢@Ikegami这个甜蜜的ASCII图表!)
问题:每个对象都有对另一个对象的引用。 。 。这意味着一旦$parent
和$child
超出范围,Perl的引用计数器仍然认为存在对每个对象的引用,因此永远不会释放内存。你在内存中找到了两个对象,无法访问其中任何一个的数据!
我的问题是:处理循环引用的正确方法是什么,以确保Perl正确处理其清理?当消除对自引用对象的所有外部引用时,如何确保Perl不会留下任何碎片?
答案 0 :(得分:12)
Scalar::Util
,特别是weaken
函数。
左值$ ref将变为弱引用。这意味着它不会在它引用的对象上保留引用计数。此外,当该对象上的引用计数达到零时,引用将设置为undef。该函数改变作为参数传递的左值,并且不返回任何值。
将您的一个或两个参考设置为" weak"当锚被破坏时,菊花链将自动解开。