2012-11-28 27 views
5

हाय मैं पर्ल वैरिएबल में बड़े स्ट्रिंग डेटा के साथ काम कर रहा हूं (इसका कच्चा ईमेल बॉडी, इसलिए इसमें संलग्नक हो सकते हैं)। पर्ल के सबस्ट्र के साथ दिलचस्प समस्या है। लगता है कि यह रिसाव है या मैं कुछ गलत कर रहा हूं (यदि हां, तो क्या?)। substr($str, 500); आदेश परपर्ल सबस्ट्र मेमोरी लीक

#!/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 

लें देखो: कोड पर विचार करें। इसके अलावा स्ट्रिंग की इसकी प्रतिलिपि (यह ठीक है), यह समान मात्रा में स्मृति को लीक करती है, इसलिए यदि आप रिटर्न वैल्यू का उपयोग दो बार स्मृति के टुकड़े करते हैं, जिसमें से एक पूरे समय स्क्रिप्ट के लिए खो जाता है ... इसके अलावा, ऐसा लगता है कि यह कोई भी नहीं है "आंतरिक बफर" की तरह है, क्योंकि यह लीक प्रत्येक कॉल ..

नोट 10 एमबी वृद्धि की यह स्थिति नहीं "फिर से उपयोगी" स्मृति के बाद से आगामी कॉल अधिक से अधिक स्मृति प्राप्त .. है

कोई सुझाव कैसे ठीक करने या उससे बचने के लिए?

मेरा पर्ल संस्करण 5.14.2; मेरे काम पर मुझे वही व्यवहार मिला (5.8.8)

+0

दिलचस्प, रिसाव पर्ल v5.12.4 और v5.14.2, लेकिन v5.16.2 नहीं होता है। – creaktive

+0

संस्करण – PSIAlt

+0

के बारे में अपडेट किया गया सबसे अच्छा हिस्सा: v5.16.2 पर भी, 'undef' स्मृति को अस्वीकार नहीं करता है! – creaktive

उत्तर

2

यदि आप $str आवंटित करने से पहले चेक करते हैं तो आपको लगभग 2 मेग्स का उपयोग केवल पर्ल चलाने के लिए किया जा रहा है। इस प्रकार $str आवंटित करने के लिए 20 मेग्स लेते हैं, स्ट्रिंग के आकार को दोगुना कर दिया जाता है। अगर मुझे लगता है कि क्या हो रहा है, तो पर्ल को 10 मेग स्ट्रिंग बनाना है और फिर इसे $str में कॉपी करना है। 20 मेग्स यह बाद में उपयोग करने के लिए आवंटित स्मृति पर रखता है।

substr($str, 0, 1)=''$str को एक नई सी स्ट्रिंग पर इंगित करने का कारण बनता है, तो आप इसे डेवेल :: पीक के साथ देख सकते हैं, लेकिन प्रक्रिया मेमोरी में वृद्धि नहीं हुई है। यह संभव है कि यह स्मृति को 'a' x 10_000_000 के लिए स्मृति आवंटित करने से मुक्त किया गया।

my $a = substr($str, 500); एक समान समस्या है। substr एक नई 10 मेग स्ट्रिंग बनाता है और फिर इसे $a में 20 मेगापिक्सल की प्रतिलिपि बनाता है। ऐसा करने के लिए और अधिक सिस्टम मेमोरी क्यों लेती है मुझे यकीन नहीं है। यह पिछले 10 मेग खंड से ऑपरेटिंग सिस्टम से प्राप्त संभावित पर्ल आवंटित स्मृति है और इसलिए यह एक भी 10 मेग का हिस्सा नहीं था और इसे ओएस से अधिक पूछना पड़ा।

undef $a निश्चित रूप से सी $a के साथ जुड़े स्ट्रिंग को साफ करता है, तो आप Devel :: पीक के साथ देख सकते हैं, लेकिन पर्ल जरूरी स्मृति वापस ऑपरेटिंग सिस्टम के लिए नहीं जारी करता है।

वैसे भी यह मेरा सबसे अच्छा अनुमान है।

लंबी कहानी छोटी, जब ऑपरेटिंग सिस्टम पर वापस प्रक्रिया द्वारा स्मृति जारी की जाती है तो जटिल और ऑपरेटिंग सिस्टम अलग-अलग होते हैं। यहां one discussion specifically about perl और one about Linux है।

+0

ठेठ एक्सएस फ़ंक्शन की तुलना में: एक्सएस फ़ंक्शंस आमतौर पर sv2mortal स्केलर (संदर्भ कमजोर हो जाता है) लौटाता है, इसलिए यदि मैं '$ a = func() लेता हूं; 'इसकी रिफाउंटउंट बढ़ रही है (कोई प्रति नहीं) या एसवी की प्रतिलिपि बनाई गई है (पहले एसवी मिटा दिया गया क्योंकि रिकॉउंट कमजोर है)। लेकिन 'substr (स्ट्रिंग, num) पर 'यह शून्य संदर्भ में भी नहीं होता है। यह मेरे लिए सबसे अजीब चीज है; यह दोनों मामलों को – PSIAlt

2

perlglossary, पर्ल internals में गहरी दफन के अनुसार, वहाँ एक thingie स्क्रैचपैड कहा जाता है:

क्षेत्र है जिसमें एक विशेष फ़ाइल या सबरूटीन की एक विशेष मंगलाचरण अपने अस्थायी मूल्यों के कुछ रहता है, सहित किसी भी lexically scoped चर।

... 
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 -MO=Concise leak.pl द्वारा बनाया गया कोड है। अब, अगर मैं कुछ डिबग झंडे (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 

तो, कि अभी स्क्रैचपैड का उपयोग करना पर्ल है।

+0

भरना नहीं है तो प्रत्येक कॉल को 'substr ($ str, 500) क्यों करें;' 10 एमबी अतिरिक्त मेमोरी खाएं? आपकी पोस्ट पर ऐसा लगता है कि इसे एक बार स्क्रैचपैड में 10 एमबी आवंटित करना होगा और इसका पुन: उपयोग करना होगा, लेकिन स्मृति प्रत्येक कॉल खो जाती है .. – PSIAlt

+0

@PSIAlt क्षमा करें, मैं 'पैडव [$ ए: 3,4] 'लाइन का उल्लेख करना भूल गया, जो कि है दूसरे स्क्रैचपैड आवंटन का स्रोत! – creaktive

+0

फिर फिर स्क्रैपपैड में पहले आवंटित स्मृति को पुन: उपयोग करने के लिए दूसरी कॉल क्यों नहीं? – PSIAlt

संबंधित मुद्दे