Perl使用GC的引用计数,并且很容易意外地进行循环引用。我看到我的程序似乎正在使用越来越多的内存,并且它可能会在几天后溢出。
有没有办法在Perl中调试内存泄漏?附加到程序并获取各种类型的对象将是一个良好的开端。如果我知道哪些对象比预期的要多得多,我可以检查所有对它们的引用并希望修复泄漏。
答案 0 :(得分:36)
Perl 永远不会将内存本身返回给系统可能是相关的:这一切都归malloc()
所有与之相关的规则。
了解malloc()
如何分配内存对于回答更大的问题非常重要,并且因系统而异,但通常大多数malloc()
实现都针对在堆栈类订单中分配和解除分配的程序进行了优化。 Perl使用引用计数来跟踪内存,这意味着解除分配意味着(与基于GC的语言不同,下面使用malloc()
)实际上并不是很难告诉去除分配的地方发生,以什么顺序发生。
您可以重新组织您的计划以利用这一事实 - 明确地调用undef($old_object)
- 并以正确的顺序,以类似于C程序员所说free(old_object);
的方式
对于长时间运行的程序(天,月等),我有大量的加载/复制/转储周期,我使用exit() and 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才能执行此操作。 / p>
答案 1 :(得分:5)
Devel::Gladiator是此领域的另一个有用工具。
答案 2 :(得分:3)
似乎cpan模块Devel::Cycle正是您所寻找的。它需要对您的代码进行一些更改,但它应该可以帮助您找到您的引用,而不会出现太多问题。
答案 3 :(得分:2)
valgrind是一个很棒的linux应用程序,用于查找运行代码中的内存泄漏。如果您的Perl代码在linux上运行,您应该检查它。
答案 4 :(得分:2)
除了其他评论之外,您可能会发现LPW2013上的Perl Memory Use talk有用。我建议观看the screencast,因为它解释了幻灯片,最后有一些可爱的视觉效果和一些Q& A.
我还建议查看我在演讲中提到的Paul Evans Devel::MAT模块。