如何在长时间运行的 Perl 程序中找到内存泄漏?

Posted

技术标签:

【中文标题】如何在长时间运行的 Perl 程序中找到内存泄漏?【英文标题】:How can I find memory leaks in long-running Perl program? 【发布时间】:2010-09-30 13:33:23 【问题描述】:

Perl 对 GC 使用引用计数,很容易意外地产生循环引用。我看到我的程序似乎使用的内存越来越多,几天后它可能会溢出。

有没有办法在 Perl 中调试内存泄漏?附加到程序并获取各种类型的对象将是一个好的开始。如果我知道哪些对象比预期的多得多,我可以检查对它们的所有引用并希望修复泄漏。

【问题讨论】:

【参考方案1】:

Perl 从不自己将内存还给系统可能是相关的:这完全取决于malloc() 以及与之相关的所有规则。

了解malloc() 如何分配内存对于回答更大的问题很重要,并且它因系统而异,但通常大多数malloc() 实现都针对程序按堆栈顺序分配和解除分配进行了优化。 Perl 使用引用计数来跟踪内存,这意味着释放意味着(与基于 GC 的语言在下面使用 malloc() 不同)实际上并不难告诉哪里会发生释放,以及按什么顺序。

您可能可以重组您的程序以利用这一事实 - 通过显式调用 undef($old_object) - 并以正确的顺序,以类似于 C 程序员所说的方式 free(old_object);

对于长时间运行的程序(几天、几个月等),我有大量的加载/复制/转储周期,我使用exit() and exec() 进行垃圾收集,而在其他方面不可行的地方,我只是打包我的数据结构(使用Storable)和文件描述符(使用$^F)和exec($0) - 通常带有像$ENVEXEC_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 才能做到这一点。

【讨论】:

@geocar,这太棒了!据我所知,这是解决复杂 perl 程序中不可避免的内存泄漏问题的唯一可靠方法。【参考方案2】:

Devel::Gladiator 是该领域的另一个有用工具。

【讨论】:

【参考方案3】:

似乎 cpan 模块 Devel::Cycle 是您正在寻找的。它需要对您的代码进行一些更改,但它应该可以帮助您找到参考资料而不会出现太多问题。

【讨论】:

【参考方案4】:

valgrind 是一个很棒的 linux 应用程序,它可以定位运行代码中的内存泄漏。如果你的 Perl 代码在 linux 上运行,你应该检查一下。

【讨论】:

我认为这行不通。 Perl 是一种解释型语言。 valgrind 不会只指向 Perl 解释器中的内存分配调用吗? 没有 valgrind 可以与 Perl 一起使用,只需使用正确的选项。它已记录在案。它需要将自己附加到已编译的可执行文件而不是 perl 二进制文件。 valgrind 会在 XS 代码中发现内存泄漏,但在 Perl 代码中不会。为此使用 Devel::Cycle 或 Devel::Leak。【参考方案5】:

除了其他 cmets,您可能会发现我在 LPW2013 上的 Perl Memory Use talk 很有用。我建议您观看the screencast,因为它解释了幻灯片,最后有一些可爱的视觉效果和一些问答。

我还建议查看我在演讲中提到的 Paul Evans Devel::MAT 模块。

【讨论】:

以上是关于如何在长时间运行的 Perl 程序中找到内存泄漏?的主要内容,如果未能解决你的问题,请参考以下文章

appium长时间运行内存溢出解决方式

长时间运行的 Python 程序(使用 Pandas)不断增加内存使用量

如何检测 Android Cursor 泄漏

Spring Boot:在长时间运行的存储过程中检测到明显的连接泄漏

Spark 驱动程序中的内存泄漏

发现 Perl 内存泄漏