简体   繁体   English

Perl内存使用情况分析和泄漏检测?

[英]Perl memory usage profiling and leak detection?

I wrote a persistent network service in Perl that runs on Linux. 我在Perl上编写了一个在Linux上运行的持久网络服务。

Unfortunately, as it runs, its Resident Stack Size (RSS) just grows, and grows, and grows, slowly but surely. 不幸的是,随着它的运行,其驻留堆栈大小(RSS)只是缓慢但肯定地增长,增长和增长。

This is despite diligent efforts on my part to expunge all unneeded hash keys and delete all references to objects that would otherwise cause reference counts to remain in place and obstruct garbage collection. 尽管我努力消除所有不需要的哈希键并删除对象的所有引用,否则会导致引用计数保留在原位并阻碍垃圾收集。

Are there any good tools for profiling the memory usage associated with various native data primitives, blessed hash reference objects, etc. within a Perl program? 是否有任何好的工具可以在Perl程序中分析与各种本机数据原语,祝福散列引用对象等相关的内存使用情况? What do you use for tracking down memory leaks? 你用什么来追踪内存泄漏?

I do not habitually spend time in the Perl debugger or any of the various interactive profilers, so a warm, gentle, non-esoteric response would be appreciated. 我不习惯在Perl调试器或任何各种交互式分析器中花费时间,因此我们将非常感谢温暖,温和,非深奥的反应。 :-) :-)

You could have a circular reference in one of your objects. 您可以在其中一个对象中使用循环引用。 When the garbage collector comes along to deallocate this object, the circular reference means that everything referred to by that reference will never get freed. 当垃圾收集器出现以释放此对象时,循环引用意味着该引用引用的所有内容永远不会被释放。 You can check for circular references with Devel::Cycle and Test::Memory::Cycle . 您可以使用Devel :: CycleTest :: Memory :: Cycle检查循环引用。 One thing to try (although it might get expensive in production code, so I'd disable it when a debug flag is not set) is checking for circular references inside the destructor for all your objects: 有一件事要尝试(虽然它可能在生产代码中变得昂贵,所以我在未设置调试标志时禁用它)是在析构函数内检查所有对象的循环引用:

# 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
}

You can use Devel::Leak to search for memory leaks. 您可以使用Devel :: Leak来搜索内存泄漏。 However, the documentation is pretty sparse... for example, just where does one get the $handle reference to pass to Devel::Leak::NoteSV() ? 但是,文档非常稀疏...例如,只有将$ handle引用传递给Devel::Leak::NoteSV() f I find the answer, I will edit this response. f我找到了答案,我将编辑此回复。

Ok it turns out that using this module is pretty straightforward (code stolen shamelessly from Apache::Leak ): 好吧,事实证明使用这个模块非常简单(代码从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";

I'd place as much code as possible in the middle section, with the leaveCount check as close to the end of execution (if you have one) as possible -- after most variables have been deallocated as possible (if you can't get a variable out of scope, you can assign undef to it to free whatever it was pointing to). 我会在中间部分放置尽可能多的代码,尽可能将leaveCount检查尽可能接近执行结束(如果你有的话) - 在大多数变量被尽可能解除分配后(如果你不能得到)一个变量超出范围,你可以为它分配undef以释放它所指向的任何东西)。

What next to try (not sure if this would be best placed in a comment after Alex's question above though): What I'd try next (other than Devel::Leak): 接下来要尝试什么(不知道在上面的Alex问题之后这是否最好放在评论中):我接下来会尝试什么(除了Devel :: Leak):

Try to eliminate "unnecessary" parts of your program, or segment it into separate executables (they could use signals to communicate, or call each other with command-line arguments perhaps) -- the goal is to boil down an executable into the smallest amount of code that still exhibits the bad behaviour . 尝试消除程序的“不必要”部分,或将其划分为单独的可执行文件(它们可以使用信号进行通信,或者使用命令行参数相互调用) - 目标是将可执行文件分解为最小量代码仍然表现出不良行为 If you're sure it's not your code that's doing it, reduce the number of external modules you're using, particularly those that have an XS implementation. 如果您确定不是您的代码正在执行此操作,请减少您正在使用的外部模块的数量,尤其是那些具有XS实现的模块。 If perhaps it is your own code, look for anything potentially fishy: 如果它可能是你自己的代码,那么找一些可能有些可疑的东西:

  • definitely any use of Inline::C or XS code 绝对使用Inline :: C或XS代码
  • direct use of references, eg \\@list or \\%hash , rather than preallocated references like [ qw(foo bar) ] (the former creates another reference which may get lost; in the latter, there is just one reference to worry about, which is usually stored in a local lexical scalar 直接使用引用,例如\\@list\\%hash ,而不是像[qw(foo bar)]这样的预分配引用(前者创建了另一个可能丢失的引用;在后者中,只有一个引用需要担心,通常存储在本地词法标量中
  • manipulating variables indirectly, eg $$foo where $foo is modified, which can cause autovivication of variables (although you need to disable strict 'refs' checking) 间接操作变量,例如$$foo ,其中$foo被修改,这可能导致变量的自动更新(尽管你需要禁用strict 'refs'检查)

I recently used NYTProf as a profiler for a large Perl application. 我最近使用NYTProf作为大型Perl应用程序的分析器。 It doesn't track memory usage, but it does trace all executed code paths which helps with finding out where leaks originate. 它不跟踪内存使用情况,但它会跟踪所有已执行的代码路径,这有助于找出泄漏源自何处。 If what you are leaking is scarce resources such as database connections, tracing where they are allocated and closed goes a long way towards finding leaks. 如果您泄漏的是稀缺资源(如数据库连接),那么在分配和关闭它们的位置进行跟踪会大大有助于发现泄漏。

Perl手册中包含了一个很好的指南: 调试Perl内存使用情况

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM