簡體   English   中英

Perl substr memory 泄漏

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM