9

我们有一个相当大的 perl 代码库。

一些运行多个小时的进程(ETL 作业)突然开始消耗比平时更多的 RAM。分析相关版本的变化是一个缓慢而令人沮丧的过程。我希望使用更自动化的分析来确定罪魁祸首。

我们的实时环境是 Debian Squeeze 上的 perl 5.14。

不过,我可以使用很多 OS X 10.5 机器。Dtrace 和 perl 似乎在这个平台上很好地结合在一起。似乎在 linux 上使用 dtrace 需要启动更多工作。我希望我们的实时系统和开发 OS X 系统之间的内存分配模式会相似——或者至少相似到足以帮助我找到这种新内存使用的来源。

这个幻灯片:

https://dgl.cx/2011/01/dtrace-and-perl

显示如何使用 dtrace 显示 perl sub 对 malloc 的调用次数。我有兴趣跟踪 perl 在进程生命周期内执行每个子程序时分配的内存总量。

关于如何做到这一点的任何想法?

4

4 回答 4

4

没有单一的方法可以做到这一点,并且逐个进行并不总是检查内存使用情况的最佳方法。我将推荐一组你可以使用的工具,一些工具可以作为一个整体工作,其他工具可以让你检查代码的单个部分或单个变量。

您可能要考虑使用Valgrind。甚至还有一个名为Test::Valgrind的 Perl 模块,它可以帮助为您的 Perl 构建设置一个抑制文件,然后检查脚本中的内存泄漏或错误。

还有Devel::Size完全符合您的要求,但在逐个变量的基础上而不是在逐个子的基础上。

您可以使用Devel::Cycle在复杂数据结构中搜索无意的循环内存引用。虽然循环引用并不意味着您在使用对象时会浪费内存,但循环引用会阻止链中的任何内容被释放,直到循环中断。

Devel::Leak比其他的更神秘一点,但它基本上可以让您获得有关在程序执行的两点之间创建和未销毁的任何SV的完整信息。如果您在子调用中检查这一点,您将知道该子例程分配的任何新内存。

您可能还想阅读 Perl 手册的perldebguts部分。

我真的无法提供更多帮助,因为每个代码库最终都会有所不同。Test::Valgrind 对于某些代码库非常有用,而在其他代码库中则非常糟糕。如果你打算尝试一下,我建议你使用最新版本的 Valgrind 并且 Perl >= 5.10,因为 Perl 5.8 和 Valgrind 在历史上相处得并不好。

于 2012-01-03T17:00:19.837 回答
2

您可能想查看Memory::UsageDevel::Size

要检查整个过程或子:

use Memory::Usage;
my $mu = Memory::Usage->new();

# Record amount of memory used by current process
$mu->record('starting work');

# Do the thing you want to measure
$object->something_memory_intensive();

# Record amount in use afterwards
$mu->record('after something_memory_intensive()');

# Spit out a report
$mu->dump();

或检查特定变量:

use Devel::Size qw(size total_size);

my $size = size("A string");

my @foo = (1, 2, 3, 4, 5);
my $other_size = size(\@foo);

my $foo = {
     a => [1, 2, 3],
     b => {a => [1, 3, 4]}
};
my $total_size = total_size($foo);
于 2012-01-04T12:46:59.580 回答
2

问题的答案是“是”。Dtrace 可用于分析 perl 进程中的内存使用情况。

这段代码:

https://github.com/astletron/perl-dtrace-malloc/blob/master/perl-malloc-total-bytes-by-sub.d

跟踪程序中每个子程序的调用和返回之间的内存使用量如何增加。作为额外的奖励,dtrace 似乎为您排序输出(至少在 OS X 上)。凉爽的。

感谢所有的插话。我自己回答了这个问题,因为这个问题确实特定于 dtrace/perl。

于 2012-02-29T09:33:52.173 回答
1

您可以基于Devel::CallTrace编写一个简单的调试模块,打印输入的 sub 以及当前进程的当前内存大小。(使用 /proc 或其他。)

于 2012-01-04T13:39:40.860 回答