我们有一个非常棒的perl代码库。
一些运行多个小时的进程(ETL作业)突然开始消耗比平常更多的RAM。分析相关版本的变化是一个缓慢而令人沮丧的过程。我希望通过更自动化的分析找出罪魁祸首。
我们的现场环境是关于Debian挤压的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在进程生命周期内执行每个sub时分配的内存总量。
关于如何做到这一点的任何想法?
答案 0 :(得分: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在历史上并不相处得很好。
答案 1 :(得分:2)
您可能需要查看Memory::Usage和Devel::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);
答案 2 :(得分:2)
问题的答案是'是'。 Dtrace可用于分析perl进程中的内存使用情况。
这段代码:
https://github.com/astletron/perl-dtrace-malloc/blob/master/perl-malloc-total-bytes-by-sub.d
跟踪程序中每个子程序的调用和返回之间内存使用量的增加情况。作为一个额外的好处,dtrace似乎为你排序输出(至少在OS X上)。凉。
感谢所有插话。我自己回答了这个问题,因为这个问题非常适合dtrace / perl。
答案 3 :(得分:1)
您可以编写一个基于Devel::CallTrace的简单调试模块,它打印输入的子信息以及当前进程的当前内存大小。 (使用/ proc或其他。)