我用 Perl 编写了一个在 Linux 上运行的持久网络服务。
不幸的是,当它运行时,它的驻留堆栈大小 (RSS) 只会增长,增长,增长,缓慢而稳定。
尽管我努力消除所有不需要的哈希键并删除对对象的所有引用,否则这些引用会导致引用计数保持在原位并阻碍垃圾收集。
是否有任何好的工具可以分析与 Perl 程序中的各种本机数据原语、祝福哈希引用对象等相关的内存使用情况?你用什么来追踪内存泄漏?
我不习惯在 Perl 调试器或任何各种交互式分析器中花费时间,因此,我将不胜感激。:-)
我用 Perl 编写了一个在 Linux 上运行的持久网络服务。
不幸的是,当它运行时,它的驻留堆栈大小 (RSS) 只会增长,增长,增长,缓慢而稳定。
尽管我努力消除所有不需要的哈希键并删除对对象的所有引用,否则这些引用会导致引用计数保持在原位并阻碍垃圾收集。
是否有任何好的工具可以分析与 Perl 程序中的各种本机数据原语、祝福哈希引用对象等相关的内存使用情况?你用什么来追踪内存泄漏?
我不习惯在 Perl 调试器或任何各种交互式分析器中花费时间,因此,我将不胜感激。:-)
您可以在其中一个对象中有循环引用。当垃圾收集器来释放这个对象时,循环引用意味着该引用所引用的所有内容都不会被释放。您可以使用Devel::Cycle和Test::Memory::Cycle检查循环引用。要尝试的一件事(尽管它在生产代码中可能会变得昂贵,所以当未设置调试标志时我会禁用它)是检查析构函数内的所有对象的循环引用:
# make this be the parent class for all objects you want to check;
# or alternatively, stuff this into the UNIVERSAL class's destructor
package My::Parent;
use strict;
use warnings;
use Devel::Cycle; # exports find_cycle() by default
sub DESTROY
{
my $this = shift;
# callback will be called for every cycle found
find_cycle($this, sub {
my $path = shift;
foreach (@$path)
{
my ($type,$index,$ref,$value) = @$_;
print STDERR "Circular reference found while destroying object of type " .
ref($this) . "! reftype: $type\n";
# print other diagnostics if needed; see docs for find_cycle()
}
});
# perhaps add code to weaken any circular references found,
# so that destructor can Do The Right Thing
}
您可以使用Devel::Leak搜索内存泄漏。但是,文档非常稀少……例如,从哪里获得 $handle 引用以传递给Devel::Leak::NoteSV()
? 如果我找到答案,我将编辑此回复。
好的,事实证明使用这个模块非常简单(代码从Apache::Leak无耻地窃取):
use Devel::Leak;
my $handle; # apparently this doesn't need to be anything at all
my $leaveCount = 0;
my $enterCount = Devel::Leak::NoteSV($handle);
print STDERR "ENTER: $enterCount SVs\n";
# ... code that may leak
$leaveCount = Devel::Leak::CheckSV($handle);
print STDERR "\nLEAVE: $leaveCount SVs\n";
我会在中间部分放置尽可能多的代码,让 leaveCount 检查尽可能接近执行结束(如果有的话)——在大多数变量尽可能被释放之后(如果你不能得到一个超出范围的变量,您可以将 undef 分配给它以释放它指向的任何内容)。
接下来要尝试什么(不确定这是否最好放在 Alex 的上述问题之后的评论中):我接下来要尝试什么(Devel::Leak 除外):
尝试消除程序中“不必要的”部分,或将其分割成单独的可执行文件(它们可以使用信号进行通信,或者可能使用命令行参数相互调用)——目标是将可执行文件简化为最小的数量仍然表现出不良行为的代码。如果您确定不是您的代码在执行此操作,请减少您正在使用的外部模块的数量,尤其是那些具有 XS 实现的模块。如果它可能是您自己的代码,请寻找任何可能可疑的内容:
\@list
or \%hash
,而不是像 [ qw(foo bar) ] 这样的预分配引用(前者会创建另一个可能会丢失的引用;在后者中,只需担心一个引用,它通常存储在局部词汇标量$$foo
where$foo
被修改,这可能导致变量自动激活(尽管您需要禁用strict 'refs'
检查)我最近使用NYTProf作为大型 Perl 应用程序的分析器。它不会跟踪内存使用情况,但会跟踪所有已执行的代码路径,这有助于找出泄漏的来源。如果您泄漏的是数据库连接等稀缺资源,那么跟踪它们的分配和关闭位置对于查找泄漏有很大帮助。
Perl 手册中有一个很好的指南:调试 Perl 内存使用