【发布时间】:2011-12-08 02:49:22
【问题描述】:
我可以通过哪种方式从 Perl 脚本中回收内存和/或防止 perl 进行内存管理池?
【问题讨论】:
-
我很想说“杀死它”和/或“一开始就不要运行它”:) “内存管理池”是什么意思?您的主机操作系统也可能会影响此处的响应。
我可以通过哪种方式从 Perl 脚本中回收内存和/或防止 perl 进行内存管理池?
【问题讨论】:
在一个并行问题上回答:In general, you cannot expect perl to release memory to the OS 在脚本完成/终止之前。终止后,所有分配的内存都会返回给操作系统,但这是操作系统的功能,不是特定于 Perl 的。
因此,如果您有一个长时间运行的脚本,那么您的选项数量是有限的:
【讨论】:
最有效的方法是拥有大量的虚拟内存,这样perl已经分配但不经常使用的内存就会被分页。
除此之外,要阻止 perl 只是随着时间的推移分配更多的内存是非常困难的……不是因为它被泄露了,而是因为 perl 真的很喜欢保留分配的东西,以防它们再次被使用。具有相当一致的字符串大小的小型代码库会在一段时间后达到顶峰,但这是一个例外情况。
在 apache 下,历史上的技术是在进程达到一定大小或在一定数量的请求后终止进程。这不适用于线程 MPM...
【讨论】:
经常取消定义,深度优先。
【讨论】:
如果操作系统愿意收回内存,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
【讨论】: