Perlの変数はCoWで共有されてもいずれCopyされるという話

https://gist.github.com/nihen/7085103

http://www.perlmonks.org/?node_id=905667

https://rt.perl.org/rt3//Public/Bug/Display.html?id=119937

http://d.hatena.ne.jp/kazuhooku/20100909/1284005880

 

大きいマスターデータなどを親プロセスで読み込んでおいて、その後forkし、子プロセスでCoWで共有する、そんな幻想を抱いていた時期が僕にもありました。

 

PerlのGCのための参照カウンタは、変数の内部にカウンターをもっているため、そのカウンターに増減があるとCoWで共有されていたメモリのうちカウンターと同一のページ内のメモリは文字通りCopyされる。

通常のコード内でそのことに気をつけたとしても、子プロセスが死ぬときにどうしてもカウンターを0に減らさなければならず、すべての変数のカウンターと同一のページは最終的にすべてCopyされるものと思わなければならない。

つまり変数とカウンターがすべて同一ページにのっているような細かいデータの集まり等をマスターデータで読み込んでいると、CoWなど最終的には意味がなくなる。

 

 2013/10/22 13:26 追記

上記の文章を読むとPerlの変数のCoWは意味がないと誤解する人もいるかもしれないのだけど、Copyされるデータはあくまで変数に付随するカウンター値と同一のページなので、変数自体が複数のページにまたがっている大きいデータ等の場合は、Copyされるのは1ページだけであるから意味が無いわけではない。また、カウンタが維持されている間は紛れも無く共有されているわけなので、下記の対策にも書いてあるとおり、カウンタ変更のタイミングを制御することにより、意味あるものとすることも可能です。誤解のなきよう。

 

対策

1. Copyされても問題のない使用メモリ容量とfork数におさえる

2. 子プロセスが一斉に死なないように慎重に配慮する。例えば Parallel::Prefork のspawn_interval がそれに使える。