2009-08-07 10 views
12

मुझे पर्ल में स्मृति के साथ कुछ समस्याएं आ रही हैं। जब मैं एक बड़ा हैश भरता हूं, तो मुझे ओएस पर वापस स्मृति जारी नहीं किया जा सकता है। जब मैं स्केलर के साथ ऐसा करता हूं और undef का उपयोग करता हूं, तो यह स्मृति को ओएस पर वापस देगा।पर्ल में, मैं ऑपरेटिंग सिस्टम में मेमोरी कैसे जारी कर सकता हूं?

यहां एक परीक्षण कार्यक्रम मैंने लिखा है।

#!/usr/bin/perl 
###### Memory test 
###### 

## Use Commands 
use Number::Bytes::Human qw(format_bytes); 
use Data::Dumper; 
use Devel::Size qw(size total_size); 

## Create Varable 
my $share_var; 
my %share_hash; 
my $type_hash = 1; 
my $type_scalar = 1; 

## Start Main Loop 
while (true) { 
    &Memory_Check(); 
    print "Hit Enter (add to memory): "; <>; 
    &Up_Mem(100_000); 
    &Memory_Check(); 

    print "Hit Enter (Set Varable to nothing): "; <>; 
    $share_var = ""; 
    $share_hash =(); 
    &Memory_Check(); 

    print "Hit Enter (clean data): "; <>; 
    &Clean_Data(); 
    &Memory_Check(); 

    print "Hit Enter (start over): "; <>; 
} 

exit; 


#### Up Memory 
sub Up_Mem { 
    my $total_loops = shift; 
    my $n = 1; 
    print "Adding data to shared varable $total_loops times\n"; 

    until ($n > $total_loops) { 
     if ($type_hash) { 
      $share_hash{$n} = 'X' x 1111; 
     } 
     if ($type_scalar) { 
      $share_var .= 'X' x 1111; 
     } 
     $n += 1; 
    } 
    print "Done Adding Data\n"; 
} 

#### Clean up Data 
sub Clean_Data { 
    print "Clean Up Data\n"; 

    if ($type_hash) { 
     ## Method to fix hash (Trying Everything i can think of! 
     my $n = 1; 
     my $total_loops = 100_000; 
     until ($n > $total_loops) { 
      undef $share_hash{$n}; 
      $n += 1; 
     } 

     %share_hash =(); 
     $share_hash =(); 
     undef $share_hash; 
     undef %share_hash; 
    } 
    if ($type_scalar) { 
     undef $share_var; 
    } 
} 

#### Check Memory Usage 
sub Memory_Check { 
    ## Get current memory from shell 
    my @mem = `ps aux | grep \"$$\"`; 
    my($results) = grep !/grep/, @mem; 

    ## Parse Data from Shell 
    chomp $results; 
    $results =~ s/^\w*\s*\d*\s*\d*\.\d*\s*\d*\.\d*\s*//g; $results =~ s/pts.*//g; 
    my ($vsz,$rss) = split(/\s+/,$results); 

    ## Format Numbers to Human Readable 
    my $h = Number::Bytes::Human->new(); 
    my $virt = $h->format($vsz); 
    my $h = Number::Bytes::Human->new(); 
    my $res = $h->format($rss); 

    print "Current Memory Usage: Virt: $virt RES: $res\n"; 

    if ($type_hash) { 
     my $total_size = total_size(\%share_hash); 
     my @arr_c = keys %share_hash; 
     print "Length of Hash: " . ($#arr_c + 1) . " Hash Mem Total Size: $total_size\n"; 
    } 
    if ($type_scalar) { 
     my $total_size = total_size($share_var); 
     print "Length of Scalar: " . length($share_var) . " Scalar Mem Total Size: $total_size\n"; 
    } 

} 

उत्पादन:

 
./Memory_Undef_Simple.cgi 
Current Memory Usage: Virt: 6.9K RES: 2.7K 
Length of Hash: 0 Hash Mem Total Size: 92 
Length of Scalar: 0 Scalar Mem Total Size: 12 
Hit Enter (add to memory): 
Adding data to shared varable 100000 times 
Done Adding Data 
Current Memory Usage: Virt: 228K RES: 224K 
Length of Hash: 100000 Hash Mem Total Size: 116813243 
Length of Scalar: 111100000 Scalar Mem Total Size: 111100028 
Hit Enter (Set Varable to nothing): 
Current Memory Usage: Virt: 228K RES: 224K 
Length of Hash: 100000 Hash Mem Total Size: 116813243 
Length of Scalar: 0 Scalar Mem Total Size: 111100028 
Hit Enter (clean data): 
Clean Up Data 
Current Memory Usage: Virt: 139K RES: 135K 
Length of Hash: 0 Hash Mem Total Size: 92 
Length of Scalar: 0 Scalar Mem Total Size: 24 
Hit Enter (start over): 

तो जैसा कि आप देख सकते हैं स्मृति नीचे चला जाता है, लेकिन यह केवल अदिश के आकार नीचे चला जाता है। कोई विचार हैश की याददाश्त कैसे मुक्त करें?

Devel::Size दिखाता है कि हैश केवल 92 बाइट्स ले रहा है भले ही प्रोग्राम अभी भी 13 9 के उपयोग कर रहा है।

+0

आपको अपनी पोस्ट को दोबारा सुधारना होगा। यह अपठनीय है। – EightyEight

+0

मैं आपको आश्वस्त कर सकता हूं कि पर्ल सिर्फ 2.7 के उपयोग नहीं कर रहा है। पीएस 1K भाग में स्मृति की रिपोर्ट करता है, आपकी मेमोरी उपयोग 1024 गुना कम है। – Schwern

उत्तर

12

सामान्य रूप से, आप ओएस को स्मृति जारी करने की उम्मीद नहीं कर सकते हैं।

अक्सर पूछे जाने वाले प्रश्न: How can I free an array or hash so my program shrinks?

आप आमतौर पर नहीं कर सकते हैं। लेक्सिकल (यानी my() चर) को आवंटित स्मृति को पुनः प्राप्त नहीं किया जा सकता है, भले ही वे दायरे से बाहर हो जाएं। यदि चर के दायरे में वापस आते हैं तो यह आरक्षित है। वैश्विक चरों को आवंटित स्मृति को और/या delete() का उपयोग करके पुन: उपयोग किया जा सकता है (आपके प्रोग्राम के भीतर)।

अधिकांश ऑपरेटिंग सिस्टम पर, किसी प्रोग्राम को आवंटित स्मृति को सिस्टम में कभी वापस नहीं किया जा सकता है। यही कारण है कि लंबे समय से चलने वाले कार्यक्रम कभी-कभी खुद को फिर से निष्पादित करते हैं। कुछ ऑपरेटिंग सिस्टम (विशेष रूप से, प्रणाली है कि स्मृति के बड़े हिस्से का आवंटन के लिए mmap(2) का उपयोग करें) याद है कि अब कोई प्रयोग किया जाता है को पुनः प्राप्त कर सकते हैं, लेकिन इस तरह के सिस्टम पर, पर्ल विन्यस्त और ओएस malloc, 'नहीं perl रों उपयोग करने के लिए संकलित किया जाना चाहिए।

अपना समय बर्बाद करने से पहले FAQ list को भी अपने कंप्यूटर पर स्थापित करना हमेशा अच्छा विचार है।

उदाहरण के लिए, How can I make my Perl program take less memory? शायद आपके मुद्दे के लिए प्रासंगिक है।

+2

आपका आरटीएफएफ लिंक बहुत अच्छा है। यह बताता है कि यह ओएस निर्भर है। यदि आपका ओएस इसका समर्थन करता है, तो आप ओएस को वापस स्मृति मुक्त कर सकते हैं। मैंने कोड लिखा है जो ओपी WinXP पर ActivePerl का उपयोग करने की इच्छा करता है। अतिरिक्त शत्रुता की कोई आवश्यकता नहीं है, कृपया अपने पहले अनुच्छेद को ठीक करने पर विचार करें। – daotoad

+0

मैंने इस अपमानजनक बम को थोड़ा सा घटा दिया। हमें आपके जैसे लोगों की जरूरत है> 10k! कृपया ऐसे जोखिम न लें। – innaM

+1

@daotoad और Manni यह एक समय मुद्दा था। जब मैंने लिखा, मूल पोस्ट एक विकृत गड़बड़ थी और केवल एक चीज जिसे मैं समझ सकता था वह पहली पंक्ति थी। उपरोक्त EightyEight द्वारा भी टिप्पणी देखें। वैसे भी, इसका ख्याल रखने के लिए धन्यवाद। –

19

आम तौर पर, हाँ, कि कैसे यूनिक्स पर स्मृति प्रबंधन काम करता है। आप हाल ही में glibc साथ लिनक्स का उपयोग कर रहे हैं, और कहा कि malloc का उपयोग कर रहे हैं, तो आप ओएस के लिए free'd स्मृति लौट सकते हैं। मुझे यकीन नहीं है कि पर्ल यह करता है, यद्यपि।

आप बड़े डेटासेट के साथ काम करने,, स्मृति में पूरी बात लोड नहीं BerkeleyDB की तरह कुछ का उपयोग करना चाहते हैं:

https://metacpan.org/pod/BerkeleyDB

उदाहरण कोड, शब्दशः चोरी:

use strict ; 
    use BerkeleyDB ; 

    my $filename = "fruit" ; 
    unlink $filename ; 
    tie my %h, "BerkeleyDB::Hash", 
       -Filename => $filename, 
       -Flags => DB_CREATE 
     or die "Cannot open file $filename: $! $BerkeleyDB::Error\n" ; 

    # Add a few key/value pairs to the file 
    $h{apple} = "red" ; 
    $h{orange} = "orange" ; 
    $h{banana} = "yellow" ; 
    $h{tomato} = "red" ; 

    # Check for existence of a key 
    print "Banana Exists\n\n" if $h{banana} ; 

    # Delete a key/value pair. 
    delete $h{apple} ; 

    # print the contents of the file 
    while (my ($k, $v) = each %h) 
    { print "$k -> $v\n" } 

    untie %h ; 

(ठीक है, verbatim नहीं। use vars का उनका उपयोग है ... विरासत ...)

आप इस तरह हैश में डेटा के गीगाबाइट स्टोर कर सकते हैं, और वाई कहां केवल स्मृति का एक छोटा सा प्रयोग करेंगे। (मूल रूप से, जो कुछ BDB के पेजर स्मृति में रखने का निर्णय लेता है, यह चलाया है।)

+1

+1 एफएक्यू उत्तर के अंतिम भाग में दी गई सलाह का उत्कृष्ट प्रदर्शन: http://faq.perl.org/perlfaq3.html#How_can_I_make_my_Pe1 –

+3

अक्सर पूछे जाने वाले प्रश्न प्रदर्शन के बारे में गलत हैं, आमतौर पर आप कैश को दबाते हैं और यह नहीं है इन-मेमोरी संरचना तक पहुंचने से अधिक महंगा (समय के संदर्भ में)। (और एक बार जब आप स्वैपिंग शुरू कर देते हैं, तो इन-मेमोरी स्ट्रक्चर डरावनी धीमी होती है, क्योंकि हैश के संदर्भ में अच्छी जगह नहीं है। मुझे कुछ ईटीएल स्क्रिप्ट लिखना याद है जो देशी हैंश के बजाय बीडीबी हैंश के साथ तीव्रता के कई ऑर्डर चलाते हैं।) – jrockway

+0

@ jrockway मुझे लगता है कि प्रदर्शन जुर्माना केवल तभी मायने रखता है जब आप स्मृति उपयोग के बारे में चिंतित नहीं होंगे: छोटे डेटा संरचनाएं जो हल्के ढंग से लोड की गई मशीन पर पूरी तरह से स्मृति में फिट होती हैं। –

8

आप पर्ल को ओएस को स्मृति जारी करने के लिए क्यों चाहते हैं? आप बस एक बड़ा स्वैप का उपयोग कर सकते हैं।

यदि आपको वास्तव में जरूरी है, तो अपना काम एक फोर्क प्रक्रिया में करें, फिर बाहर निकलें।

+4

यह उत्तर एक डाउनवोट के लायक नहीं है। लंबे समय तक चलने वाले कार्यक्रमों में स्मृति उपयोग में अच्छी तरह से परिभाषित अस्थायी स्पाइक्स से निपटने के लिए एक फोर्कड प्रक्रिया पूरी तरह से उचित तरीका है। –

+0

समस्याएं हैं, सर्वर के पास 3 जीबी रैम है। ओएस के लिए 1 जीबी और MySQL के लिए 1 जीबी। मेरी प्रक्रिया 27 एमबी से शुरू होगी और यह लगभग 800 एमबी तक पहुंच जाएगी। तब सिस्टम स्वैप में जाना शुरू कर देगा और सब कुछ धीमा कर देगा। कांटा के साथ समस्या यह है कि यह सभी 800 एमबी को नई प्रक्रिया में कॉपी करेगा। – clintonm9

+0

इसके अलावा, इसमें और अधिक जोड़ने के लिए; मैं अलग-अलग चीजों को असीमित करने के लिए विभिन्न धागे का उपयोग कर रहा हूं। धागे का उपयोग करें; उपयोग धागे :: साझा; थ्रेड :: कतार का उपयोग करें; तो मैं डेटा को एक साझा हैश पर पास कर दूंगा, फिर दूसरा धागा डेटा को संसाधित करेगा जैसा कि यह आता है। यह कई धागे को अलग-अलग चीजों से गुजरता है। मैं किसी बिंदु पर अनुमान लगा रहा हूं कि हैश बहुत बड़ा हो रहा है, और बहुत सारी मेमोरी ले रहा है। शायद सामान्य रूप से इसके दौरान एक बेहतर तरीका है? विभिन्न कांटा प्रक्रिया के साथ मेरी समस्या यह है कि डेटा को आगे और आगे पार करना बहुत कठिन लगता है। कोई विचार? – clintonm9

0

सिस्टम malloc और मुफ्त का उपयोग करने के लिए विकल्प -Uusemymalloc के साथ perl recompiling कोशिश करें। आप कुछ अलग-अलग परिणाम देख सकते हैं

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