简体   繁体   English

如何从perl中回收内存?

[英]How can I reclaim memory from perl?

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

As answered on a parallel question : In general, you cannot expect perl to release memory to the OS before the script is finished/terminated. 正如在并行问题上所回答的: 通常,在脚本完成/终止之前,您不能指望perl向操作系统释放内存 Upon termination all the memory allocated is given back to the OS, but that's an OS feature and isn't Perl-specific. 终止后,所有分配的内存都会返回给操作系统,但这是一个操作系统功能,并不是特定于Perl的。

So you have a limited number of options if you have a long-running script : 因此,如果您有一个长时间运行的脚本,那么您的选项数量有限:

  • You delegate memory-intensive parts to child processes. 您将内存密集型部件委派给子进程。 This way the memory will be freed when each part is finished. 这样,每个部件完成后,内存将被释放。 The price to pay is IPC communications. 支付的价格是IPC通信。
  • You use your own memory-managed structures, usually based on Tie . 您使用自己的内存管理结构,通常基于Tie The price to pay is to handle the load/store to/from backstore if you structure isn't a simple one (even a standard NDBM-based Hash is simple but quite powerful though). 如果您的结构不是一个简单的(甚至标准的基于NDBM的Hash虽然很简单但功能非常强大),付出的代价是处理来自/从backstore的加载/存储。
  • You use you memory as a precious ressource, and optimize its usage (by using smaller constructs, enabling memory reuse, etc). 您将内存用作宝贵的资源,并优化其使用 (通过使用较小的构造,启用内存重用等)。

The most effective method is to have plenty of virtual memory, so that memory that perl has allocated but is not frequently using just gets paged out. 最有效的方法是拥有足够的虚拟内存,以便perl分配但不经常使用的内存只会被分页。

Other than that, it is extremely difficult to keep perl from just allocating more memory over time...not because it is leaked, but because perl really likes to keep things allocated in case they are used again. 除此之外,保持perl不仅仅是随着时间的推移分配更多的内存是非常困难的......不是因为它被泄露了,而是因为perl非常喜欢分配内容以防再次使用它们。 A small codebase with fairly consistent string sizes will top out after a bit, but that is an exceptional case. 一个具有相当一致的字符串大小的小代码库将在一点之后达到顶峰,但这是一个例外情况。

Under apache, the historic technique has been to kill off a process when it reaches a certain size, or after a certain number of requests. 在apache下,历史性的技术是在达到一定大小时或在一定数量的请求之后终止进程。 This doesn't work so well with threaded MPMs... 使用线程MPM时,这不能很好地工作......

Undef经常,深度优先。

Perl "supports" returning memory to the operating system if the operating system is willing to take that memory back. 如果操作系统愿意将内存恢复,则Perl“支持”将内存返回给操作系统。 I use the quotes because, IIRC, Perl does not promise when it will give that memory back. 我使用引号是因为,IIRC,Perl并没有承诺什么时候它会给回忆。

Perl currently does promise when destructors will run, when objects will be deallocated (and, especially, in what order that will happen). 当析构函数将被运行时,Perl当前会做出承诺,当对象将被释放时(特别是,将以什么顺序发生)。 But deallocated memory goes to a pool for Perl to use later and that memory -- eventually -- is released to the operating system if the operating system supports it. 但是,释放的内存会进入池中以供Perl稍后使用,并且如果操作系统支持,则最终将内存释放到操作系统。

I had a similar problem where I'm reading in a large SOAP message from the server. 我有一个类似的问题,我正在从服务器读取一个大的SOAP消息。 As far as I can tell, SOAP::Lite can't stream the data, so it has to load it all into memory before I can process it. 据我所知, SOAP::Lite无法传输数据,因此在处理数据之前必须将其全部加载到内存中。

Even through I only need a small list as the result, it causes the memory footprint of the program to be in the gigabytes. 即使通过我只需要一个小列表,它也会导致程序的内存占用量达到千兆字节。 This is a problem, because the script does a lot of network communication, causing the memory to remain allocated for a long time. 这是一个问题,因为脚本会进行大量的网络通信,导致内存长时间保持分配状态。

As mentioned before, the only true solutions are a) redesign everything, or b) fork/exec. 如前所述,唯一真正的解决方案是a)重新设计所有内容,或b)fork / exec。 I have here an example of fork/exec that should work to illustrate the solution: 我这里有一个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__);
}

This will run forever, producing output like this: 这将永远运行,产生如下输出:

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