
このシェルスクリプトがbashで徐々に多くのメモリを消費するのはなぜですか?ローカル変数を使用しません。の値は直ちに終了するcpid
ので、繰り返すたびに変更されますが、大きすぎるべきではls
ありません。
関連するシェルスクリプトは単に子プロセスを監視し、そのプロセスが開始されたことを確認します。スクリプトが呼び出されます。run-always
set -euf
# monitor a child process
# see if it's up
cpid=
while : ; do
# if cpid isn't set, spawn child
if [ -z "$cpid" ]; then
"$@" &
cpid="$!"
fi
# if child isn't active unset cpid
if ps -o pid= -p "$cpid"; then
:
else
cpid=
fi
sleep 1
done
すぐに終了するプロセス(例ls
:)にこれを使用すると、スクリプトを実行すると次のメモリ使用量が発生します。dash run-always ls
4476kbで、絶対に大きくなりません。
これは、Linuxで毎秒メモリ使用量を取得するために使用するコマンドです。から直接メモリと最大メモリ使用量を取得する方法があるかもしれませんが、ps
これで作業が完了します。
while : ; do cat /proc/"$(ps a | grep run-always | grep -v grep | awk '{print $1}')"/status | grep -i 'vmsize\|vmpeak' ; sleep 1; done
を使用して上記のスクリプトを実行すると、dash
メモリ使用量はまったく増加せず、私のコンピュータ上で着実に4476kbを維持します。
ただし、bash()を使用すると、bash run-always ls
10秒ごとに数キロバイトのメモリがさらに割り当てられ、決して解放されません。
バッシュはなぜこのようなことをするのか?
出力例:
VmPeak: 16676 kB
VmSize: 16676 kB
VmPeak: 16676 kB
VmSize: 16676 kB
VmPeak: 16676 kB
VmSize: 16676 kB
VmPeak: 16676 kB
VmSize: 16676 kB
VmPeak: 16676 kB
VmSize: 16676 kB
VmPeak: 16676 kB
VmSize: 16676 kB
VmPeak: 16676 kB
VmSize: 16676 kB
VmPeak: 16676 kB
VmSize: 16676 kB
VmPeak: 16676 kB
VmSize: 16676 kB
VmPeak: 16676 kB
VmSize: 16676 kB
VmPeak: 16676 kB
VmSize: 16676 kB
VmPeak: 16680 kB
VmSize: 16680 kB
VmPeak: 16680 kB
VmSize: 16680 kB
VmPeak: 16680 kB
VmSize: 16680 kB
VmPeak: 16680 kB
VmSize: 16680 kB
VmPeak: 16680 kB
VmSize: 16680 kB
VmPeak: 16680 kB
VmSize: 16680 kB
VmPeak: 16680 kB
VmSize: 16680 kB
VmPeak: 16680 kB
VmSize: 16680 kB
VmPeak: 16680 kB
VmSize: 16680 kB
VmPeak: 16684 kB
VmSize: 16684 kB
VmPeak: 16684 kB
VmSize: 16684 kB
VmPeak: 16684 kB
VmSize: 16684 kB
VmPeak: 16684 kB
VmSize: 16684 kB
VmPeak: 16684 kB
VmSize: 16684 kB
VmPeak: 16684 kB
VmSize: 16684 kB
VmPeak: 16684 kB
VmSize: 16684 kB
VmPeak: 16684 kB
VmSize: 16684 kB
VmPeak: 16684 kB
VmSize: 16684 kB
VmPeak: 16684 kB
VmSize: 16684 kB
VmPeak: 16684 kB
VmSize: 16684 kB
VmPeak: 16684 kB
VmSize: 16684 kB
VmPeak: 16684 kB
VmSize: 16684 kB
VmPeak: 16684 kB
VmSize: 16684 kB
VmPeak: 16688 kB
VmSize: 16688 kB
VmPeak: 16688 kB
VmSize: 16688 kB
VmPeak: 16688 kB
VmSize: 16688 kB
VmPeak: 16688 kB
VmSize: 16688 kB
VmPeak: 16688 kB
VmSize: 16688 kB
VmPeak: 16688 kB
VmSize: 16688 kB
VmPeak: 16688 kB
VmSize: 16688 kB
VmPeak: 16688 kB
VmSize: 16688 kB
VmPeak: 16688 kB
VmSize: 16688 kB
VmPeak: 16688 kB
VmSize: 16688 kB
VmPeak: 16692 kB
VmSize: 16692 kB
答え1
Bash は、アクティブな作業テーブルに各バックグラウンド プロセスを保持します。以前のジョブを明示的に確認せずに新しいジョブを作成するため、テーブルが無制限に大きくなる可能性があります。次のバックグラウンドプロセスを開始する前にプロセスをバックグラウンドに進めるか、disown
終了ステータスを確認すると問題が消えます。jobs
たとえば、このスクリプトバージョンはメモリ使用量を増やしません。
set -euf
# monitor a child process
# see if it's up
cpid=
while : ; do
# if cpid isn't set, spawn child
if [ -z "$cpid" ]; then
"$@" &
disown $! # Don't waste memory on this red-headed child
cpid="$!"
fi
# if child isn't active unset cpid
if ps -o pid= -p "$cpid"; then
:
else
cpid=
fi
sleep 1
done
答え2
この問題はダッシュで発生しないことがわかったので、これがバグによって発生する可能性が最も高いことは明らかです。
bash-3.xを使用すると成長しますが、非常に遅くなります。それでも他のシェルよりも高速です。
あなたのbashバージョンに関連するバグレポートを書くことをお勧めします。
注:いくつかのテストをしましたが、どれだけ待ってもまったく成長しないシェルは2つだけです。そして、mksh
元のシェルはsbrk()の代わりにmalloc()を使用するように変換されませんでした。Bourne Shell
他のすべての殻は非常にゆっくりと成長します。