11

我最近问了一个关于在 Perl 中覆盖对象和内存管理的问题。我收到的其中一个答案通知我,我最近编写的脚本可能有问题。

我有一个包含一些非常复杂的数据结构的脚本,这些数据结构有很多parent->child / child->parent关系。这也意味着有许多对象具有循环引用。根据this answer,如果处理不当,循环引用可以“欺骗” Perl 的引用计数机制并导致内存泄漏。


循环引用示例:

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

免责声明——这不是我的史诗作品——感谢@Ikegami 提供了这个可爱的 ASCII 图表!

问题:每个对象都有对另一个的引用。. . 这意味着一旦超出范围,Perl 的引用计数器仍然认为对每个对象的引用都存在,因此永远不会释放内存$parent$child你最终在内存中有两个对象,无法访问它们中的任何一个的数据!


我的问题是: 处理循环引用以确保 Perl 正确处理其清理的正确方法是什么?当对自引用对象的所有外部引用都被消除时,如何确保 Perl 不会留下任何碎片?

4

1 回答 1

13

Scalar::Util特别是weaken功能。

左值 $ref 将变成弱引用。这意味着它不会对它引用的对象进行引用计数。此外,当该对象的引用计数达到零时,该引用将设置为 undef。此函数改变作为其参数传递的左值并且不返回任何值。

将您的一个或两个引用设置为“弱”,当锚点被破坏时,菊花链将自动解开。

于 2015-08-14T13:20:31.750 回答