Perl v5.10.1是否存在内存泄漏问题,或如何解读valgrind结果。

5
我有一个存在内存泄漏的脚本。我认为出现这种情况是因为在对嵌套对象执行 undef 后,脚本中的内存量没有改变。我使用了 Devel::Cycle 来定位任何循环引用,并将这些循环引用转换为弱引用,使用了 Scalar::Util。问题仍然存在。

现在我正在尝试使用 Valgrind 来解决这个问题。作为开始使用 valgrind 的第一步,我测试了一下 Perl 的 hello world 程序:

#! /usr/bin/perl

use strict;
use warnings;

print "Hello world!\n";

运行 valgrind --trace-children=yes perl ./hello_world.pl 时,以下是 valgrind 输出的内容:

==12823== HEAP SUMMARY:
==12823==     in use at exit: 290,774 bytes in 2,372 blocks
==12823==   total heap usage: 5,159 allocs, 2,787 frees, 478,873 bytes allocated
==12823==
==12823== LEAK SUMMARY:
==12823==    definitely lost: 13,981 bytes in 18 blocks
==12823==    indirectly lost: 276,793 bytes in 2,354 blocks
==12823==      possibly lost: 0 bytes in 0 blocks
==12823==    still reachable: 0 bytes in 0 blocks
==12823==         suppressed: 0 bytes in 0 blocks
==12823== Rerun with --leak-check=full to see details of leaked memory
==12823==
==12823== For counts of detected and suppressed errors, rerun with: -v
==12823== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 6 from 6)

这里了解到,当allocs的数量不等于frees的数量时会出现内存泄漏。
由于我只是打印hello world,我不得不问一个问题,Perl解释器本身在这里(v5.10.1)是否至少有自己的内存泄漏,或者我完全理解错了?
在着手处理我的实际perl脚本之前,我想弄清楚这个问题。 补充说明 我在Perl 5.12.0 delta中看到以下内容:

对哈希表的弱引用将泄漏。这影响了DBI [RT #56908]。

这可能最终适用于我完整的perl脚本,而不是这个hello world程序,但这使我认为我应该通过非root方式安装最新版本的perl。 补充说明2 我已经安装了ActiveState Perl 5.16.3,但问题仍然存在,也存在于我的实际脚本中。
我怀疑在这个hello world程序的情况下,我必须错误地使用/解释valgrind,但我还没有弄清楚具体在哪里。 更新1 Daxim的答案确实有所不同。当我在perl脚本中添加以下行时:
use Perl::Destruct::Level level => 1;

然后是valgrind的输出:

==29719== HEAP SUMMARY:
==29719==     in use at exit: 1,617 bytes in 6 blocks
==29719==   total heap usage: 6,499 allocs, 6,493 frees, 585,389 bytes allocated
==29719==
==29719== LEAK SUMMARY:
==29719==    definitely lost: 0 bytes in 0 blocks
==29719==    indirectly lost: 0 bytes in 0 blocks
==29719==      possibly lost: 0 bytes in 0 blocks
==29719==    still reachable: 1,617 bytes in 6 blocks
==29719==         suppressed: 0 bytes in 0 blocks
==29719== Rerun with --leak-check=full to see details of leaked memory
==29719==
==29719== For counts of detected and suppressed errors, rerun with: -v
==29719== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 6 from 6)

这是一个很大的差别。我的脚本自己的内存泄漏问题仍然存在,但至少这个hello world程序现在对valgrind来说似乎是合理的。

然而,整个问题是,如果没有这个有点难懂的Perl::Destruct::Level模块的使用,除了在程序退出时没有释放内存外,停止硬循环引用的Scalar::Util有什么意义???

2个回答

4

这个泄漏是有意的。vincent in #p5p 评论道:

分配的内存只有在设置了 PERL_DESTRUCT_LEVEL 后才会被释放,因为让操作系统处理更快。PERL_DESTRUCT_LEVEL 只在调试版本中可用,或者通过使用 Perl::Destruct::Level 模块从 perl 中获取。


那么,如何使用valgrind来区分这种泄漏和用户脚本中的泄漏呢?此外,这是否意味着在perl脚本执行期间无法释放内存 - 它的内存消耗只能增长而不能缩小? - EMiller
请跟随我的帖子中的超链接,以查阅精美的文档。 - daxim

0
据我所知(如有错误请指正——我没有阅读代码,文档也非常少),问题在于,在典型的Perl程序中,有很多东西会被分配但在程序结束前不会被释放。这包括像全局变量这样的东西,但也包括编译后的程序代码本身。
现在,Perl可以在程序结束时释放所有这些东西使用的内存,但事实证明通常没有太大意义,因为操作系统会自行处理。一个例外是当类似valgrind这样的工具正在查看程序结束时是否有任何未释放的内存,并假设任何这样的内存必须已经泄漏了。
因此,基本上,Perl通常是懒惰的,当它知道它即将退出并让操作系统来处理它时,就不会费心去释放内存。设置PERL_DESTRUCT_LEVEL告诉Perl清理那些内存,以向valgrind这样的工具表明它实际上并没有泄漏。
无论如何,据我所知,这些都不会影响程序执行期间的内存管理。如果您在程序运行时将某个东西的引用计数减少到零(例如通过让变量超出范围或直接覆盖最后一个引用),它将被释放,而与 PERL_DESTRUCT_LEVEL 无关。
但是,请注意,这通常仅释放 perl 自身重复使用的内存 - 除了一些罕见情况,如显式 mmap(),在现代具有虚拟内存的操作系统上运行的任何程序实际上都很少释放内存页面。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接