2009-08-07 21 views
12

私はPerlのメモリにいくつかの問題があります。大きなハッシュを埋めると、メモリがOSに戻されることはありません。私がスカラーで同じことをしてundefを使うと、メモリはOSに戻されます。Perlでは、オペレーティングシステムにどのようにメモリを解放できますか?

私が書いたテストプログラムです。

#!/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"; 
    } 

} 

OUTPUTは:

 
./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は、プログラムがまだ139Kを使用していても、ハッシュが92バイトしか占めていないことを示しています。

+0

投稿を再フォーマットする必要があります。それは判読不能です。 – EightyEight

+0

私は、Perlがわずか2.7Kを使用していないことを保証することができます。 psは1Kチャンクでメモリを報告しますが、メモリ使用量は1024時間になりません。 – Schwern

答えて

12

一般に、perlがメモリをOSにリリースするとは期待できません。

FAQ:How can I free an array or hash so my program shrinks?をご覧ください。

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

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

また、あなたの時間を無駄にする前に、コンピュータにインストールされ、FAQ listを読み取るために、常に良い考えです。

たとえば、How can I make my Perl program take less memory?が問題と関連している可能性があります。

+2

あなたのRTFFリンクはとても良いです。これはOSに依存していることが指摘されています。ご使用のOSがサポートしている場合は、メモリーを解放してOSに戻すことができます。私は、OPがWinXP上でActivePerlを使用することを望むものを正確に行うコードを書いています。余分な敵意は必要ありません。あなたの最初の段落を修正することを検討してください。 – daotoad

+0

私はこの攻撃力のある爆弾を少し解きました。私たちにはあなたのような人々に10K以上の代表者が必要です!そのようなリスクを取らないでください。 – innaM

+1

@daotoadとManniタイミングの問題でした。私がそれを書いたとき、元のポストは不正なフォーマットであり、私が見分けられるのは最初の行だけでした。上記のEightyEightによるコメントも参照してください。とにかく、世話をしてくれてありがとう。 –

19

一般的に、そうですね、それはUNIXでのメモリ管理の仕組みです。最近のglibcでLinuxを使用していて、そのmallocを使用している場合は、空きメモリをOSに返すことができます。私はPerlがこれをしているのかどうかはわかりません。

あなたが大規模なデータセットで作業したい場合は、メモリに全部をロードしない、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 ; 

を(OK、逐語的ではありません。use varsの使用は...旧式です...)

この方法では、ギガバイトのデータをハッシュに格納できます.y ouはわずかなメモリしか使用しません。 (基本的に、BDBのページャがメモリ内に保持することを決めるものであれば、これは制御可能です。)

+1

+1よくある質問回答の最後の部分にあるアドバイスの優れたデモンストレーション:http://faq.perl.org/perlfaq3.html#How_can_I_make_my_Pe1 –

+3

よくある質問はパフォーマンスについては間違っています。通常はキャッシュに当たっていますが、これはいいえですメモリ内構造にアクセスするよりも(時間的に)コストがかかります。 (ネイティブハッシュの代わりにBDBハッシュを結ぶと、数桁速く走るETLスクリプトを書くことが覚えています) – jrockway

+0

@ jrockway私は、パフォーマンスのペナルティは、メモリ使用量を心配する必要がない場合にのみ重要であると推測します。軽量なマシン上のメモリに完全に収まる小さなデータ構造。 –

8

なぜPerlがメモリをOSにリリースしたいのですか?より大きなスワップを使うことができます。

本当に必要な場合は、作業を二股で行い、終了してください。

+4

この答えは、downvoteに値するものではありません。フォークされたプロセスは、長時間実行されているプログラムでのメモリ使用量の明確に定義された一時的なスパイクに対処するための完全に合理的な方法です。 –

+0

問題は、サーバーに3 GBのラムがあることです。 OSは1GB、MySQLは1GB。私のプロセスは27MBから始まり、約800MBになるでしょう。その後、システムがスワップに移行し、すべての処理が遅くなります。フォークの問題は、すべての800 MBを新しいプロセスにコピーすることです。 – clintonm9

+0

また、これをさらに追加するには、私は異なるスレッドを使用して、さまざまなことを非同期で行います。 スレッドを使用します。 スレッドを使用する::共有; スレッド:キューを使用します。 私は共有ハッシュにデータを渡し、それから入ってくるデータを別のスレッドが処理します。これは、さまざまなことをする多くのスレッドに渡されます。私はハッシュが非常に大きくなり、多くのメモリを占有していると推測しています。 これは一般的により良い方法がありますか?異なるforkプロセスの私の問題は、データを前後に渡すことがずっと難しいようです。 考えていますか? – clintonm9

0

オプション-Uusemymallocを使用してperlを再コンパイルして、システムmallocを使用してfreeを試してみてください。いくつかの異なる結果が表示される場合があります。

関連する問題