繁体   English   中英

如何从perl中回收内存?

[英]How can I reclaim memory from perl?

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

正如在并行问题上所回答的: 通常,在脚本完成/终止之前,您不能指望perl向操作系统释放内存 终止后,所有分配的内存都会返回给操作系统,但这是一个操作系统功能,并不是特定于Perl的。

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

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

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

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

在apache下,历史性的技术是在达到一定大小时或在一定数量的请求之后终止进程。 使用线程MPM时,这不能很好地工作......

Undef经常,深度优先。

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

当析构函数将被运行时,Perl当前会做出承诺,当对象将被释放时(特别是,将以什么顺序发生)。 但是,释放的内存会进入池中以供Perl稍后使用,并且如果操作系统支持,则最终将内存释放到操作系统。

我有一个类似的问题,我正在从服务器读取一个大的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

暂无
暂无

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

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