symfony+propelで数千回ループするバッチを走らせたところメモリリークしてどうしても途中で処理が終了してしまう。 調べた所、phpのガベコレのシステムで変数を循環参照させてしまうと、変数の参照カウンタが0にならずにメモリを開放してくれないのが原因だった。
propelで one-to-many のリレーションをしているテーブルを扱う場合、 $one_object->addManyObject($many_object); といったメソッドがあるのだがこのメソッドに循環参照するコードが含まれていてメモリリークしていた。数千回ループ回すバッチとかで使用する時は要注意。
public function addManyObject(ManyObject $l)
{
$this->collManyObjects[] = $l;
$l->setOneObject($this); // ここで循環参照している
}
検証コード:
for($i=0; $i<100; ++$i) {
$one_object = new OneObject();
$one_object->addManyObject(new ManyObject());
echo memory_get_usage() . "\n";
}
出力:
2147424
2149220
2151240
2153580
2155968
2158356
2160744
2163160
2165576
2167992
...
どんどん増える。
解決策はこの手のメソッドは使わない。PHP5.3から解決策が出てくるらしい。symfony+propelはメモリ使うなぁ。