Perl 对 GC 使用引用计数,很容易意外地进行循环引用。我看到我的程序似乎正在使用越来越多的内存,并且可能会在几天后溢出。
有没有办法在 Perl 中调试内存泄漏?附加到程序并获取各种类型的对象将是一个好的开始。如果我知道哪些对象比预期的多得多,我可以检查对它们的所有引用并希望修复泄漏。
Perl 对 GC 使用引用计数,很容易意外地进行循环引用。我看到我的程序似乎正在使用越来越多的内存,并且可能会在几天后溢出。
有没有办法在 Perl 中调试内存泄漏?附加到程序并获取各种类型的对象将是一个好的开始。如果我知道哪些对象比预期的多得多,我可以检查对它们的所有引用并希望修复泄漏。
Perl永远不会自己将内存还给系统可能是相关的:这完全取决于malloc()
与此相关的所有规则。
了解如何malloc()
分配内存对于回答更大的问题很重要,并且它因系统而异,但通常大多数malloc()
实现都针对程序按堆栈顺序分配和释放进行了优化。Perl 使用引用计数来跟踪内存,这意味着释放意味着(与malloc()
在下面使用的基于 GC 的语言不同)实际上并不难判断释放将在哪里发生以及以什么顺序发生。
可能你可以重新组织你的程序以利用这个事实——通过undef($old_object)
显式调用——并以正确的顺序,以类似于 C 程序员所说的方式free(old_object);
对于长时间运行的程序(几天、几个月等),我有大量的加载/复制/转储周期,我使用垃圾收集exit() and exec()
,而在其他范围内不可行的地方,我只是打包我的数据结构(使用Storable
)和文件描述符(使用$^F
)和exec($0)
- 通常设置一个类似的环境变量,即使您自己没有任何泄漏,您$ENV{EXEC_GC_MODE}
也可能需要类似的东西,因为 Perl 正在泄漏您的系统无法弄清楚如何回馈的小块.malloc()
当然,如果您的代码确实存在泄漏,那么我的其余建议会更相关。它最初发布到关于这个主题的另一个问题,但它没有明确涵盖长期运行的程序。
所有 perl 程序内存泄漏要么是一个持有引用的 XS,要么是一个循环数据结构。如果您知道哪些结构可能包含循环,则Devel::Cycle是查找循环引用的好工具。Devel::Peek可用于查找引用计数高于预期的对象。
如果您不知道该去哪里寻找,Devel::LeakTrace::Fast可能是一个不错的选择,但您需要一个为调试而构建的 perl。
如果您怀疑泄漏在 XS 空间内,那就更难了,而Valgrind可能是您最好的选择。Test::Valgrind可能会帮助您减少需要搜索的代码量,但这在 Windows 上不起作用,因此您必须将(至少是泄漏的部分)移植到 Linux 才能做到这一点。
Devel::Gladiator是该领域的另一个有用工具。
似乎 cpan 模块Devel::Cycle是您正在寻找的。它需要对您的代码进行一些更改,但它应该可以帮助您找到参考资料而不会出现太多问题。
valgrind是一个很棒的 linux 应用程序,它可以定位运行代码中的内存泄漏。如果您的 Perl 代码在 linux 上运行,您应该检查一下。
除了其他评论之外,您可能会发现我在 LPW2013 上的Perl Memory Use 演讲很有用。我建议观看截屏视频,因为它解释了幻灯片,最后有一些可爱的视觉效果和一些问答。
我还建议查看我在演讲中提到的 Paul Evans Devel::MAT模块。