您好我正在使用Perl变量中的大字符串数据(其原始电子邮件正文,因此它可以包含附件).与Perl的substr有趣的问题.似乎它的泄漏或我做错了什么(如果是,什么?).考虑代码:
#!/usr/local/bin/perl
use strict;
my $str = 'a'x10_000_000;
system("ps up $$"); #22mb used (why?)
#USER PID %CPU %MEM VSZ RSS TT STAT STARTED TIME COMMAND
#alt 64398 0,0 0,2 33292 22700 7 S+J 22:41 0:00,03 /usr/local/bin/perl ./t.pl
substr($str, 0, 1)='';
system("ps up $$"); #No leak
#USER PID %CPU %MEM VSZ RSS TT STAT STARTED TIME COMMAND
#alt 64398 0,0 0,2 33292 22732 7 S+J 22:41 0:00,04 /usr/local/bin/perl ./t.pl
substr($str, 500);
system("ps up $$"); #Leaked 10Mb (why?!)
#USER PID %CPU %MEM VSZ RSS TT STAT STARTED TIME COMMAND
#alt 64398 0,0 0,3 43532 32520 7 S+J 22:41 0:00,05 /usr/local/bin/perl ./t.pl
my $a = substr($str, 500);
system("ps up $$"); #Leaked 10Mb + Copyed 10Mb
#USER PID %CPU %MEM VSZ RSS TT STAT STARTED TIME COMMAND
#alt 64398 0,0 0,5 64012 52096 7 S+J 22:41 0:00,09 /usr/local/bin/perl ./t.pl
undef $a; #Free scalar's memory
system("ps up $$"); #Free'd 10Mb
#USER PID %CPU %MEM VSZ RSS TT STAT STARTED TIME COMMAND
#alt 64398 0,0 0,4 53772 42308 7 S+J 22:41 0:00,09 /usr/local/bin/perl ./t.pl
# Total leaked 2 times for 10Mb each
Run Code Online (Sandbox Code Playgroud)
看看substr($str, 500);命令.另外它的字符串的返回副本(没关系),它泄漏了相同数量的内存,所以如果你使用返回值它的两块内存,其中一个在整个时间脚本工作中丢失...而且,似乎它不是任何一种"内部缓冲区",因为它泄漏了每个调用..
注意这种10Mb增加的情况不是"重用"内存,因为后续调用会获得越来越多的内存.
有任何建议如何修复或避免?
我的Perl版本5.14.2; 我的工作相同的行为(5.8.8)
如果你ps在分配之前进行检查,$str你会发现大约 2 兆被用来运行 perl。因此分配$str需要 20 兆,是所创建字符串大小的两倍。如果我必须猜测发生了什么,perl 必须创建一个 10 meg 字符串,然后将其复制到$str. 20兆。它保留分配的内存以供以后使用。
substr($str, 0, 1)=''导致$str指向一个新的 C 字符串,您可以使用 Devel::Peek 看到这一点,但进程内存并没有增加。它可能使用了从分配内存中释放的内存'a' x 10_000_000。
my $a = substr($str, 500);有类似的问题。创建substr一个新的 10 兆字符串,然后将其复制到$a需要的 20 兆字符串中。我不确定为什么需要更多的系统内存来执行此操作。Perl 可能从操作系统获得的前一个 10 meg 块中分配了内存,因此不再是单个 10 meg 块,它必须向操作系统请求更多内存。
undef $a肯定会清除与 关联的 C 字符串$a,您可以使用 Devel::Peek 看到,但 perl 不一定将内存释放回操作系统。
无论如何,这是我最好的猜测。
长话短说,当进程将内存释放回操作系统时,过程很复杂,并且操作系统的处理方式有所不同。这里有一场专门关于 perl 的讨论和一场关于 Linux 的讨论。