如何从perl中回收内存?

时间:2009-11-03 06:44:32

标签: perl memory-management

我可以通过Perl脚本回收内存和/或防止perl进入内存管理池的方式是什么?

5 个答案:

答案 0 :(得分:9)

在脚本完成/终止之前回答并行问题:In general, you cannot expect perl to release memory to the OS。终止后,所有分配的内存都会返回给操作系统,但这是一个操作系统功能,并不是特定于Perl的。

如果您有一个长时间运行的脚本,那么您的选项数量有限:

  • 您将内存密集型部件委派给子进程。这样,每个部件完成后,内存将被释放。支付的价格是IPC通信。
  • 您使用自己的内存管理结构,通常基于Tie。如果您的结构不是一个简单的(甚至标准的基于NDBM的Hash虽然简单但功能非常强大),付出的代价是处理来自/从backstore的加载/存储。
  • 您将内存用作宝贵的资源,optimize its usage(通过使用较小的构造,启用内存重用等)。

答案 1 :(得分:8)

最有效的方法是拥有足够的虚拟内存,以便perl分配但不经常使用的内存只会被分页。

除此之外,保持perl不仅仅是随着时间的推移分配更多内存是非常困难的......不是因为它被泄露了,而是因为perl非常喜欢分配内容以防再次使用它们。一个具有相当一致的字符串大小的小代码库将在一点之后达到顶峰,但这是一个例外情况。

在apache下,历史性的技术是在一个进程达到一定大小时或在一定数量的请求之后终止进程。这对线程MPM来说效果不好......

答案 2 :(得分:2)

Undef经常,深度优先。

答案 3 :(得分:2)

如果操作系统愿意将内存恢复,Perl“支持”将内存返回给操作系统。我使用引号是因为,IIRC,Perl并没有承诺什么时候会给你回忆。

Perl目前确实会在析构函数运行时做出承诺,当对象将被释放时(特别是,将以何种顺序发生)。但是,释放的内存会转移到池中供Perl使用,如果操作系统支持,则最终将内存释放到操作系统。

答案 4 :(得分:0)

我有一个类似的问题,我正在从服务器读取一个大的SOAP消息。据我所知,SOAP::Lite无法传输数据,因此在处理数据之前必须将其全部加载到内存中。

即使我只需要一个小列表,它也会导致程序的内存占用量达到千兆字节。这是一个问题,因为脚本会进行大量的网络通信,导致内存长时间保持分配状态。

如前所述,唯一真正的解决方案是a)重新设计所有内容,或b)fork / exec。我这里有一个fork / exec的例子,它应该用来说明解决方案:

# 
# in general, perl will not return allocated memory back to the OS.
#
# to get around this, we must fork/exec

sub _m($){
    my $ln = shift;
    my $s = qx/ ps -o rss,vsz $$ | grep -v RSS /;
    chomp($s);
    print STDERR "$$: $s $ln>\n";
}

sub alloc_dealloc(){
    # perldoc perlipc for more interesting
    # ways of doing this fork:
    defined(my $pid = open(KID,'-|')) || die "can't fork $!";

    my $result = -1;
    if($pid){
        my $s = <KID>; eval $s;
    }else{
        _m(__LINE__);
        my $a = [];

        # something that allocates a lot of memory...
        for($i=0;$i<1024*1024*16;$i++){
            push(@$a,int(rand(3)));
        }
        _m(__LINE__);

        # something that processes that huge chunk
        # of memory and returns a very small result
        my $r=0;
        for(@$a){ $r+=$_; }

        _m(__LINE__);
        @$a = ();
        _m(__LINE__);
        undef($a);
        _m(__LINE__);

        # STDOUT goes to parent process
        print('$result = '.$r.";\n");
        exit;
    }

    return $result;
}

while(1){ 
    _m(__LINE__);
    my $r = alloc_dealloc(); 
    print "Result: $r\n";
    _m(__LINE__);
}

这将永远运行,产生如下输出:

9515:  1892  17876 54>
9519:   824  17876 24>
9519: 790004 807040 31> # <-- chunk of memory allocated in child
9519: 790016 807040 38>
9519: 790068 807040 41> 
9519: 527924 544892 43> # <-- partially free()d, but mostly not
9515:  1976  17876 57> # <-- parent process retains its small footprint
Result: 16783001