Perl では、巨大な読み取り専用データ構造を一度生成すると、fork()
.
これは、フォーク時に RSS ページで COW を利用するためです。これは非常にうまく機能しますが、子プロセスが終了すると、終了する直前に itelf からすべての RAM が割り当てられます。
この無駄な割り当てを回避する方法はありますか?
この問題を示すサンプル Perl コードを次に示します。
#! /usr/bin/perl
my $a = [];
# Allocate 100 MiB
for my $i (1 .. 100000) {
push @$a, "x" x 1024;
}
# Fork 10 other process
for my $j (1 .. 10) {
last unless fork();
}
# Sleep for a while to be able to see the RSS
sleep(5);
サンプルvmstat
出力では、最初に 100MiB のみを割り当て、次に 1 回目のスリープ後に短時間全体を割り当て、その後すべてを解放することがわかります。
procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu------
r b swpd free buff cache si so bi bo in cs us sy id wa st
0 0 0 1329660 80596 86936 0 0 21 18 160 25 0 0 100 0 0
1 0 0 1328048 80596 86936 0 0 0 0 1013 44 0 0 100 0 0
0 0 0 1223888 80596 86936 0 0 0 0 1028 76 11 5 84 0 0
0 0 0 1223888 80596 86936 0 0 0 0 1010 40 0 0 100 0 0
0 0 0 1223888 80596 86936 0 0 0 0 1026 54 0 0 100 0 0
0 0 0 1223888 80596 86936 0 0 0 0 1006 39 0 0 100 0 0
13 0 0 741156 80596 86936 0 0 0 0 1012 66 13 58 28 0 0
0 0 0 1329288 80596 86936 0 0 0 0 1032 60 0 0 100 0 0
注: Perl のバージョン固有の問題ではないようです。5.8.8、5.10.1、および 5.14.2 をテストしたところ、すべてこの動作を示しました。
アップデート:
@choroba がコメントで尋ねたようにundef
、データ構造も試してみましたが、RAM が割り当てられるとメモリタッチがトリガーされるようです。
最初のスクリプトの最後に次のスニペットを追加できます。
# Unallocate $a
undef $a;
# Sleep for a while to be able to see the RSS
sleep(5);