如何从perl中回收内存?

如何从perl中回收内存?,perl,memory-management,Perl,Memory Management,从Perl脚本中回收内存和/或防止Perl进行内存管理池的方法是什么?最有效的方法是拥有大量虚拟内存,这样Perl分配但不经常使用的内存就可以被调出 除此之外,要阻止perl随着时间的推移只分配更多的内存是非常困难的……这不是因为它被泄漏了,而是因为perl真的喜欢保留分配的内存,以防它们再次被使用。一个字符串大小相当一致的小代码库将在一段时间后结束,但这是一个例外情况 在apache下,历史上的技术一直是在进程达到一定大小时或在一定数量的请求后终止进程。这对线程化MPM不太管用…通常是取消定义

从Perl脚本中回收内存和/或防止Perl进行内存管理池的方法是什么?

最有效的方法是拥有大量虚拟内存,这样Perl分配但不经常使用的内存就可以被调出

除此之外,要阻止perl随着时间的推移只分配更多的内存是非常困难的……这不是因为它被泄漏了,而是因为perl真的喜欢保留分配的内存,以防它们再次被使用。一个字符串大小相当一致的小代码库将在一段时间后结束,但这是一个例外情况


在apache下,历史上的技术一直是在进程达到一定大小时或在一定数量的请求后终止进程。这对线程化MPM不太管用…

通常是取消定义,深度优先。

正如一个平行问题所回答的:在脚本完成/终止之前。终止时,所有分配的内存都会返回给操作系统,但这是操作系统的一个特性,不是特定于Perl的

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

  • 将内存密集型部分委托给子进程。这样,当每个部分完成时,内存将被释放。付出的代价是IPC通信
  • 您使用自己的内存管理结构,通常基于。如果你的结构不是一个简单的结构(即使是一个标准的基于NDBM的散列也很简单,但功能相当强大),那么要付出的代价就是处理从backstore到backstore的加载/存储
  • 您将内存用作宝贵的资源,并且(通过使用较小的构造、启用内存重用等)
如果操作系统愿意收回内存,Perl“支持”将内存返回到操作系统。我使用引号是因为,IIRC,Perl不能保证何时会返回内存


Perl目前确实承诺何时运行析构函数,何时释放对象(特别是以什么顺序释放对象)。但是,释放的内存会进入一个池供Perl以后使用,如果操作系统支持,该内存最终会释放到操作系统。

我遇到了一个类似的问题,我正在从服务器读取一条大的SOAP消息。据我所知,
SOAP::Lite
无法对数据进行流式处理,因此在我处理数据之前,它必须将数据全部加载到内存中

即使我只需要一个小的列表作为结果,它也会导致程序的内存占用以GB为单位。这是一个问题,因为脚本执行大量网络通信,导致内存长时间保持分配状态

如前所述,唯一真正的解决方案是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__);
}
#
#一般来说,perl不会将分配的内存返回操作系统。
#
#要解决这个问题,我们必须fork/exec
子单位(元){
我的$ln=班次;
my$s=qx/ps-o rss,vsz$$| grep-v rss/;
咀嚼($s);
打印标准“$$:$s$ln>\n”;
}
次级分配{
#perldoc perlipc更有趣
#做这件事的方法:
定义(my$pid=open(KID,'-|')| | die“不能叉$!”;
我的$result=-1;
如果($pid){
my$s=;eval$s;
}否则{
_m(线);
我的$a=[];
#分配大量内存的东西。。。
对于($i=0;$i)
9519:   824  17876 24>
9519: 790004 807040 31> # 
9519: 790068 807040 41> 

9519:527924 544892 43>##我很想说“杀死它”和/或“一开始就不要运行它”:)你说的“内存管理池”是什么意思?您的主机操作系统可能也会影响响应。深度优先不应该有任何区别,除非您有其他对深度内容的引用。这似乎与我的经验一致——在我的经验中,任何数量的取消定义或容器对象的破坏都不会减少程序的内存占用。
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