2016-11-13 9 views
2

私が書いたperlスクリプトのメモリ使用に関するいくつかの問題があります(下記のコード)。スクリプトはいくつかの変数を開始し、それらをデータで満たしてから、それらを再び定義解除します。しかし、すべてを削除した後のスクリプトのメモリ使用量は、データを含まないためにはまだまだ高いものです。メモリからperlオブジェクトを削除する方法

psには、スクリプトは最初の39秒間に1.027 Mbのメモリ(RSS)を使用します(foreachループの前のすべて)。その後、メモリ使用量が上昇し始め、204.391 Mbから172.410 Mbの間で変動します。しかし、スクリプトの最後の10秒(すべてのデータが削除されるはずです)でも、メモリ使用量は決して172.410Mbを下回りません。

変数とその中のすべてのデータを(スクリプトのメモリ使用量を減らすために)perlで永久に削除する方法はありますか?もしそうなら、どうすればいいですか?

use strict; 
use warnings; 

sleep(30); 

my $ELEMENTS = 1_000_000; 
my $MAX_ELEMENT = 1_000_000_000; 
my $if_condition = 1; 

sleep(5); 

my %hash = (1 => {}, 2 => {}, 3 => {}, 4 => {}); 

foreach my $key (keys %hash){ 
    if($if_condition){ 
     my $arrref1 = [ (rand($MAX_ELEMENT)) x $ELEMENTS ]; 
     my $arrref2 = [ (rand($MAX_ELEMENT)) x $ELEMENTS ]; 
     my $arrref3 = [ (rand($MAX_ELEMENT)) x $ELEMENTS ]; 

     sleep(2); 

     if(!defined($hash{$key}->{'amplification'})){ 
      $hash{$key}->{'amplification'} = []; 
     } 

     push(@{$hash{$key}->{'amplification'}},@{$arrref1}); 
     undef($arrref1); 
     push(@{$hash{$key}->{'amplification'}},@{$arrref2}); 
     undef($arrref2); 
     push(@{$hash{$key}->{'amplification'}},@{$arrref3}); 
     undef($arrref3); 


     sleep(3); 

     delete($hash{$key}); 

     sleep(5); 
    } 
} 

sleep(10); 
+0

170メガバイトはあまりありません。なぜあなたはとても保守的である必要がありますか?これは組み込みシステムですか? – Borodin

+0

'[(rand($ MAX_ELEMENT))x $ ELEMENTS]'は、同じ数の1,000,000個のコピーを持つ配列を作成するでしょうか? – Borodin

+0

大きな数字に数千の区切り文字を追加しました( '1_000_000_000')。これはPerlの構文的糖の1つです:[Perlによって無視されるwhitin数を強調し、読みやすさを向上させるかもしれない](http://perldoc.perl。org/perldata.html#スカラー値コンストラクタ)。 – PerlDuck

答えて

6

Perlのよくある質問3 - あなたは通常使用できないHow can I free an array or hash so my program shrinks?

。字句(つまりmy()変数)に割り当てられたメモリ は、範囲外になっても再利用または再利用できません。変数がスコープに戻った場合は、 が予約されています。 をグローバル変数に割り当てたメモリは、 undef()および/またはdelete()を使用して(プログラム内で)再利用できます。

ほとんどのオペレーティングシステムでは、プログラムに割り当てられたメモリ は決してシステムに返されません。そのため、長時間実行されているプログラムは、時には自分自身で再実行されることがあります( )。いくつかの操作 システム(特に、大きなチャンクを割り当てるためにmmap(2)を使用するシステム)は、使用されなくなったメモリを再利用できますが、 システムでは、OSのmallocを使用するようにperlを設定してコンパイルする必要があります。 perlのものではありません。

一般に、メモリの割り当てと割り当て解除は、 ではなく、Perlで心配する必要があります。

も参照してください 「Perlプログラムのメモリ使用量を減らすにはどうすればよいですか?」

+0

少なくともPOSIXシステムでは効率的ではありません。 POSIXでは、 'malloc'と' free'は最適な汎用メモリ管理のために最適化されています。あなた自身をローリングすることは、コードを複製することである。 – shawnhcorey

+0

@ shawnhcorey私はp5pがあなたとの改善について話し合うことを確信しています –

0

通常、perlはメモリをシステムに戻しません。別の目的のために必要な場合に備えて、独自のメモリプールを保持します。これは、字句データがループ内で頻繁に使用されるため、多くのことが起こります。例えば、$arrref1の変数は、100万要素の配列を参照します。これらの配列のメモリがシステムに返され、ループのたびに再割り当てされると、大きなペナルティが発生する可能性があります。

私が書いたように、170MBは大したものではありませんが、一時配列を作成し、そのリストを直接ハッシュ要素に追加します。現状では、あなたが不必要に各配列

の2つのコピーを維持していることは、次のようになります

use strict; 
use warnings 'all'; 

sleep 30; 

use constant ELEMENTS => 1_000_000; 
use constant MAX_ELEMENT => 1_000_000_000; 

my $if_condition = 1; 

sleep 5; 

my %hash = (1 => {}, 2 => {}, 3 => {}, 4 => {}); 

foreach my $key (keys %hash) { 

    next unless $if_condition; 


    sleep 2; 

    push @{ $hash{$key}{amplification} }, (rand MAX_ELEMENT) x ELEMENTS; 
    push @{ $hash{$key}{amplification} }, (rand MAX_ELEMENT) x ELEMENTS; 
    push @{ $hash{$key}{amplification} }, (rand MAX_ELEMENT) x ELEMENTS; 


    sleep 3; 

    delete $hash{$key}; 

    sleep 5; 
} 

sleep 10; 
+0

私の小さなスクリプトはできるだけ効率的に書かれていませんが、意図的に上に貼り付けられたコードはより複雑なスクリプト(私はここに貼り付けることはできません)。そこでは、3つの一時配列は関数の結果であり、その関数の出力は同じままでなければなりません。 – user1834095

関連する問題