3

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);
4

1 に答える 1