5

我有一个存在内存泄漏的脚本。我相信这是因为在我undef对嵌套对象执行之后,脚本中的内存量没有改变。我已经使用Devel::Cycle来定位任何循环引用,并且我已经将这些循环引用转换为带有Scalar::Util. 问题仍然存在。

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

#! /usr/bin/perl

use strict;
use warnings;

print "Hello world!\n";

这是运行时的 valgrind 输出valgrind --trace-children=yes perl ./hello_world.pl

==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,但我还不明白在哪里。

UPDATE1 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 来说似乎是明智的。

这整个事情虽然引出了一个问题,Scalar::Util如果在程序退出之前没有释放内存,那么停止硬循环引用有什么意义呢Perl::Destruct::Level

4

2 回答 2

4

泄漏是故意的。#p5p评论中的文森特:

除非设置了PERL_DESTRUCT_LEVEL ,否则分配的内存实际上不会被释放,因为让操作系统处理它会更快。PERL_DESTRUCT_LEVEL 仅可用于调试构建或使用perl 中的Perl::Destruct::Level

于 2013-06-12T17:14:15.933 回答
1

据我了解(如果我错了,请纠正我——我没有阅读代码,而且文档似乎很少),关键是,在一个典型的 Perl 程序中,会有很多东西已分配,但在程序结束之前不会被释放。这包括诸如全局变量之类的东西,还包括例如编译后的程序代码本身。

现在,perl可以在程序结束时释放用于所有这些东西的内存,但事实证明这通常没有多大意义,因为无论如何操作系统都会这样做。一个例外是当 valgrind 之类的东西正在查看在程序结束时是否有任何未释放的内存,并假设任何此类内存必须已经泄漏。

因此,基本上,perl 通常是懒惰的,当它知道它即将退出并让操作系统处理它时,它不会打扰释放内存。设置 PERL_DESTRUCT_LEVEL 告诉 perl 无论如何都要清理该内存,只是为了向 valgrind 之类的工具显示它实际上并没有泄漏。

无论如何,这些,AFAIK,都不会影响程序执行期间的内存管理。如果您在程序运行时将某事物的引用计数减少到零(例如,通过让变量超出范围,或通过直接覆盖最后一个引用),它将被释放,而不管 PERL_DESTRUCT_LEVEL。

但是,请注意,这通常只会释放内存以供 perl 自身重用——除了一些罕见的情况,如显式 mmap(),对于在具有虚拟内存的现代操作系统上运行的任何程序实际上将内存页面释放回操作系统是非常不寻常的当它运行时。

于 2013-12-06T00:56:58.230 回答