(Zshのガベージコレクション)序Zshは極めて強力なシェルだが、大規模プログラミングにおいて使われることは少ない。designにおいてはシェルスクリプトは強力な武器だ。できれば積極的に活用していきたい。なると、Zshにおいて明らかでない、あるいは公知ではないことと付き合っていかなければならない。$countdoneのような処理を行うスクリプトを、invoke_workerがファイルを読み込むのではなく、事前に読み込んでおくことでワーカーの処理時間を短縮したいということだ。&donewaitのようにしたいということだ。問題は「これがメモリを食いつぶさないか」ということである。普通のスクリプトの場合、この方法はほとんど効果をもたらさない。したらマイナスになるかもしれない。そもそもこれらの情報が「単純にファイルとして読み込むだけ」の設計になっているところも工夫のなせる技なのだが、必ずしもそのようにできるわけではない。クラスタ仕様になっているとファイルアクセスが遅いかもしれないし、その違いを吸収するためにさらに別の方法をとるかもしれないのだ。&donewaitワーカーは起動数も多く、当然ながら処理としては重い。逐次実行されるワーカー部分であまりその処理を担わせたくない。設定のほうは起動される全てのワーカーにとって共通である。これを環境変数にするメリットは大きい。Linuxのfork(2)はコピーオンライトだ。configは文字列であり、起動されるワーカーではその文字列をパースすることになるから、この$config環境変数が変更されることはない。この環境変数は実体はひとつであり、常に同一の実体が参照される。コピーされることもないので速度が上がる。ディスクIOとメモリへのコピーが2回目以降省略できるのだ。環境変数で渡す文字列は「システムコールがCライブラリである」ためにC文字列(の配列)であり、\000が含まれていると文字列がそこで終わってしまう。私は勘違いと慎重さを欠いたことから赤っ恥をやらかしてしまった。データのほうは、ほぼ単純に、ワーカー実行中に時間がかかる(かもしれない)データの取得を裏でやっておきたい、ということである。これも環境変数にしてしまえばワーカーはリード時間をとられない。所要時間の総量は変わらないが、裏でやることで逐次実行部分に含めることを避けるということである。"$count")"というのが100万回実行されるということだ。これはループのたびに異なる値になる。Zshにガベージコレクタがなければ100万件のデータを抱えてしまうことになり、これはメモリ消費量的にまずい。いうわけで、「Zshは変数を上書きしたらメモリを開放してくれる(ガベージコレクションしてくれる)のか?」という疑問を解き明かす必要ができた。doneのようにしてメモリ消費量を監視すれば良い。ちなみに、100Mを指定しているが、/dev/urandomは一度に読めるのは32MiBまでである。8034021564080332803328034843344803408034080332803322156368034080332だいたい2倍程度と見ていいと思うのだが、ときどき3.5倍程度まで増加する。だいたい2倍ということはかなり迅速にメモリを回収してくれている印象だ。実際のワーカーはこんなに長時間実行はしないので、実際のワーカーの実行時間に近い感じにしてみよう。1089328034019530080340215628803402114721116168033217864443344215644回収しきれないタイミングが増えてメモリ使用量にばらつきは生じているが、回収ペースを上回ってメモリ消費量が果てしなく増えていくようなことはないようだ。追加の注意点フルスケールするように設計されているワーカーの場合、CPUコア数を使い切るだけワーカーを起動していると、結果的に裏で色々するためのコンテキストスイッチコストが高くついて全体では遅くなる可能性もある。いうか、ワーカーの実行がそれほど時間のかからないものであるならばwaitの時間は短くなり、waitの時間が短くなるほどスケール阻害要素としては大きくなる。