关于Perl内存利用率的问题

时间:2011-10-17 21:51:44

标签: perl memory memory-leaks

SO社区,

我最近一直在讨论两个内存问题,我遇到了一些我的perl脚本,我希望我在这里找到一些帮助/指针,以便更好地了解正在发生的事情。

可疑的观察#1:

我在不同的服务器实例(本地笔记本电脑macosx,专用服务器硬件,虚拟服务器硬件)上运行相同的perl脚本,并且在跟踪的内存消耗中获得了显着不同的结果。在脚本初始化之后,一个实例将报告脚本的内存消耗为210 MB,而另一个盒子的内存消耗为330 MB,这是一个超过60%的波动。据我所知,负责Perl“垃圾收集”的malloc()函数是特定于操作系统的,但偏差是否正常,或者我应该更仔细地查看发生了什么?

可疑的观察#2:

一个内存泄漏的脚本相对简单:

foreach(@dataSamples) {

  #memorycheck_1

  my $string = subRoutine($_);
  print FILE $string;

  #memorycheck_2

}

子例程中的所有变量都保持在本地,并且在子例程完成后应该超出范围。然而,在#memorycheck_1和#memorycheck_1检查内存使用情况时,存在严重的内存泄漏。

有没有解释?使用Devel :: Leak似乎有泄漏的指针,我很难理解他们将来自哪里。有没有一种简单的方法可以将Devel :: Leak的响应转化为实际上可以指出那些泄漏引用来源的指针?

由于

2 个答案:

答案 0 :(得分:3)

您有两个不同的问题:

1)为什么不同环境下的内存占用量不相同?

嗯,所有操作系统都涉及64位吗?或者有混合?如果一个OS是32位而另一个是64位,则可以预期变化。或者,正如@hobbs在评论中指出的那样,是perl之一用线程支持编译而另一个不是?

2)为什么检查#1和检查#2之间的内存占用量会发生变化?

这并不一定意味着存在内存泄漏。 Perl不会向操作系统返回内存。程序的内存占用量将是它达到的最大占用空间,并且不会下降。

这两点都不是Perl特有的。有关更多详细信息,您需要显示更多详细信息。

另请参阅C FAQ中的Question 7.25和FAQ条目中提到的further reading

答案 1 :(得分:3)

Perl中内存泄漏的最常见原因是循环引用。最简单的形式将是:

sub subRoutine {
    my( $this, $that );
    $this = \$that;
    $that = \$this;
    return $_[0];
}

当然,人们阅读时可能会说,“为什么会有人这样做?”一般不会。但是更复杂的数据结构可以很容易地包含循环引用,我们甚至不会眨眼它们。考虑双链表,其中每个节点引用其左侧和右侧的节点。重要的是不要让这个列表的最后一个显式引用超出范围而不先破坏每个节点中包含的循环引用,否则你将获得一个不可访问但不能被垃圾收集的结构,因为引用每个节点的计数永远不会降到零。

每{{}}},核心模块Eric Strom's excellent suggestion有一个名为weaken的函数。已被削弱的引用不会对其引用的实体持有引用计数。这有助于防止循环引用。另一种策略是在类中实现循环引用的数据结构,其中对象方法显式地破坏循环引用。无论哪种方式,这种数据结构都需要小心处理。

另一个麻烦来源是写得不好的XS模块(没有什么可以对抗XS作者;编写XS模块真的很棘手)。在XS模块关闭的门后面发生的事情可能是内存泄漏。

在我们看到subRoutine内部发生的事情之前,我们只能猜测是否存在问题,以及问题的根源可能是什么。