[英]Perl substr memory leak
嗨,我正在使用 Perl 變量(其原始 email 主體,因此它可以包含附件)中的大字符串數據。 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
看看substr($str, 500);
命令。 除了它的字符串的返回副本(沒關系),它泄漏了相同數量的 memory,所以如果你使用返回值它的兩次 memory 其中一個丟失了整個時間腳本工作......而且,似乎它不是任何一種“內部緩沖區”,因為它會泄漏每個調用..
請注意,這種增加 10Mb 的情況不是“重復使用”memory,因為后續調用會越來越多 memory..
有什么建議可以解決或避免這種情況嗎?
我的 Perl 版本 5.14.2; 我在工作中遇到的相同行為(5.8.8)
如果你在分配$str
之前堅持使用ps
檢查,你會發現只有2兆用於運行perl。 因此,分配$str
需要20兆,是正在創建的字符串的兩倍。 如果我不得不猜測發生了什么,perl必須制作一個10兆字符串,然后將其復制到$str
。 20兆。 它保留在以后使用的分配內存。
substr($str, 0, 1)=''
導致$str
指向一個新的C字符串,你可以用Devel :: Peek看到它,但進程內存不會增加。 它可能會使用釋放的內存來為'a' x 10_000_000
分配內存。
my $a = substr($str, 500);
有一個類似的問題。 substr
創建一個新的10兆字符串,然后將其復制到需要20兆的$a
。 為什么需要更多的系統內存才能做到這一點我不確定。 它可以從操作系統獲得的前一個10兆字節塊中分配內存,因此不再是單個10兆字節塊,它不得不向操作系統詢問更多內容。
undef $a
肯定會清除與$a
關聯的C字符串,你可以看到Devel :: Peek,但是perl不一定會將內存釋放回操作系統。
無論如何,這是我最好的猜測。
簡而言之,當一個進程將內存釋放回操作系統時,操作系統很復雜,而操作系統則采用不同的方式。 這里有一個關於perl的討論和一個關於Linux的 討論 。
根據Perlglossary ,埋入Perl內部深處,有一個名為scratchpad的東西:
特定文件或子例程的特定調用保留其某些臨時值的區域,包括任何詞法范圍的變量。
這是perl -MO=Concise leak.pl
生成的代碼:
...
10 <;> nextstate(main 3 leak.pl:30) v:*,&,{,x*,x&,x$,$ ->11
15 <2> sassign vKS/2 ->16
13 <@> substr[t16] sK/2 ->14
- <0> ex-pushmark s ->11
11 <0> padsv[$str:2,4] s ->12
12 <$> const(IV 500) s ->13
14 <0> padsv[$a:3,4] sRM*/LVINTRO ->15
16 <;> nextstate(main 4 leak.pl:35) v:*,&,{,x*,x&,x$,$ ->17
...
觀察padsv[$str:2,4]
語句。 現在,如果我使用一些調試標志運行代碼( perl -DmX leak.pl
),“泄漏”的來源變得更加清晰:
USER PID %CPU %MEM VSZ RSS TT STAT STARTED TIME COMMAND
stas 55970 1.5 0.3 2454528 21548 s001 S+ 6:11PM 0:00.04 perl -DmX leak.pl
...
Pad 0x7f8a328062c8[0x7f8a3240d040] sv: 16 sv=0x7f8a32833298
0x7f8a3240a2a0: (02222) free
0x10d013000: (02223) malloc 9999500 bytes
...
Pad 0x7f8a328062c8[0x7f8a3240d040] sv: 15 sv=0x7f8a328332c8
0x7f8a3240a560: (02231) free
0x10d99d000: (02232) malloc 9999500 bytes
...
USER PID %CPU %MEM VSZ RSS TT STAT STARTED TIME COMMAND
stas 55970 1.5 0.5 2474064 41084 s001 S+ 6:11PM 0:00.06 perl -DmX leak.pl
所以,這就是使用暫存器的Perl。
不是 substr() 導致雙倍 memory 使用,而是 x 運算符。 如果您使用 vec($a, 10000000, 8) = 0; 而不是 x 運算符,那么將只使用適量的 memory!
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.