Perl 使用引用计数进行 GC,很容易意外地产生循环引用。我发现我的程序似乎使用了越来越多的内存,几天后它可能会溢出。
有什么方法可以调试 Perl 中的内存泄漏吗?附加到程序并获取各种类型的对象数量将是一个好的开始。如果我知道哪些对象比预期的数量多得多,我可以检查对它们的所有引用并希望修复泄漏。
最佳答案
Perl 永远不会自行将内存返还给系统,这可能是相关的:这完全取决于 malloc()
以及与之相关的所有规则。
了解malloc()
如何分配内存对于回答更大的问题很重要,并且它因系统而异,但一般来说大多数malloc()
实现都是优化的用于以类似堆栈的顺序分配和取消分配的程序。 Perl 使用引用计数来跟踪内存,这意味着释放意味着(与底层使用 malloc()
的基于 GC 的语言不同)实际上并不那么难告诉 释放将在哪里发生以及以什么顺序发生。
您可能可以重新组织您的程序以利用这一事实 - 通过显式调用 undef($old_object)
- 以正确的顺序,以类似于 C 的方式 -程序员说free(old_object);
对于长时间运行的程序(几天、几个月等),我有大量的加载/复制/转储周期,我使用 exit() 和 exec()
进行垃圾收集,并且在哪里这是不可行的,我只是打包我的数据结构(使用 Storable
)和文件描述符(使用 $^F
)和 exec($0)
- 通常使用像 $ENV{EXEC_GC_MODE}
这样的环境变量设置,即使您自己没有任何泄漏,您也可能需要类似的东西,因为 Perl 是泄漏系统 malloc()
无法弄清楚如何归还的小块。
当然,如果您的代码确实存在泄漏,那么我的其余建议会更相关。最初发布于to another question on this subject ,但它没有明确涵盖长时间运行的程序。
<小时/>所有 Perl 程序内存泄漏要么是 XS 持有引用,要么是循环数据结构。 Devel::Cycle如果您知道哪些结构可能包含循环,那么它是查找循环引用的好工具。 Devel::Peek可用于查找引用计数高于预期的对象。
如果您不知道还能去哪里查看,Devel::LeakTrace::Fast可能是一个不错的首选,但您需要构建一个用于调试的 perl。
如果你怀疑泄漏是在 XS 空间内部,那就更难了,并且 Valgrind可能会是您最好的选择。 Test::Valgrind可能会帮助您减少需要搜索的代码量,但这在 Windows 上不起作用,因此您必须将(至少是泄漏部分)移植到 Linux 才能做到这一点。
关于perl - 如何在长时间运行的 Perl 程序中发现内存泄漏?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/429254/