我有一个在mod_perl中运行的Perl脚本需要将大量数据写入客户端,可能需要很长时间。我观察到的行为是,一旦我打印并刷新某些东西,即使我rflush
(我知道操作系统无法回收它),也不会回收缓冲存储器。
这是mod_perl的运作方式,有没有办法可以强制它定期释放缓冲区内存,以便我可以将它用于新的缓冲区,而不是从操作系统中获取更多内容?
为了澄清,我自己没有使用任何缓冲区,我的代码中没有泄漏。请考虑以下简单示例:
sub handler {
my $request = shift;
my $boundary = time;
$request->content_type("multipart/x-mixed-replace;boundary=\"$boundary\";");
for (;;) {
$request->print("--$boundary\n");
$request->print("Content-type: text/html; charset=utf-8;\n\n");
$request->print("$data\n\n");
$request->rflush;
}
return Apache2::Const::OK;
}
这种情况严重泄漏,我的请求仍然存在,因此可能会持续数天。
答案 0 :(得分:2)
不将内存返回给操作系统是perl
解释器本身的标准行为,而不是特定于mod_perl本身。除了使用共享内存(IIRC,您手动处理分配/解除分配)或终止进程之外,我不知道有任何方法让perl
将内存释放回主机操作系统。
让变量超出范围将允许perl
为其他变量重用该内存,但不会将其返回给操作系统。
编辑:我只是重新阅读了这个问题,并意识到您只是想找到一种方法让perl
重新使用内存,而不是试图将其释放到OS。在这种情况下,使用词法(my
)变量并将它们限制在尽可能小的范围内,而不是提前定义全局缓冲区并永久保存它应该可以解决问题。
答案 1 :(得分:0)
你的for(;;)循环永远不会像写入那样结束,这会导致比泄漏内存更糟的问题。 print方法必须分配一些内存,可能作为请求记录的一部分,通常在清理请求时释放。这发生在C代码中,在mod_perl2或Apache2中。
你必须重新设计你的方法来解决这个问题。而不是从mod_perl处理程序中发送长时间运行的响应,将用户通过ProxyPass设置重定向到将打印响应到STDOUT的程序。 (基本上是一个CGI脚本。)脚本可以是纯perl,其他海报提到的关于限制变量范围的技术将起作用。响应仍将通过Apache,但是当作为反向代理运行时,Apache有一组固定的缓冲区,它可以通过bucket-chigade复制数据;我从未见过我的反向代理进程消耗了大量内存,尽管传递了大量数据。
答案 2 :(得分:-1)
释放您对缓冲区的所有引用。例如,如果您使用字符串作为
中的缓冲区$buf = "really long string " . "and other methods that make it huger";
print SOMEWHERE $buf;
$buf = ""; # or undef $buf according to taste
应该将以前由$ buf指向的存储空间返回到空闲池。