環境
FuelPHP 1.7.2
発端
taskで数万件のレコードを操作する処理をしていたら、メモリ不足エラーが出てしまったので原因を調査。
再現
下記のソースで確認、再現。
for($i=0; $i<1000; $i++) {
echo memory_get_usage(true), " usage.\n";
$row = Model::find($i);
unset($row);
}
for($i=0; $i<1000; $i++) {
echo memory_get_usage(true), " usage.\n";
$row = new Model();
$row->save();
unset($row);
}
また、下記のものではメモリ消費量の増加はみられなかった
for($i=0; $i<1000; $i++) {
echo memory_get_usage(true), " usage.\n";
$row = Model::find('first');
unset($row);
}
for($i=0; $i<1000; $i++) {
echo memory_get_usage(true), " usage.\n";
$row = Model::find('first');
$row->set('aaa', $i);
$row->save();
unset($row);
}
結論
どうやらORMでレコードを取得・追加する際に、プライマリキーを使ってスタティック変数に保存してしまうみたい。
(Model.php
のstatic::$_cached_objects
を参照。__construct()
,create()
,find()
などで使われている)
そんでもっていくら格納され続けても開放されないため、そこにどんどんデータが溜まっていってメモリ不足、という流れになっている。
確かに何度もDBに問い合わせが飛ぶのを防ぐという意味ではスタティック変数とかに格納しておくのはいいんだけれど、これはこれで困ってしまう気もするなぁ。
格納する処理自体はConfigでもOFFにできない様子なので、Modelクラス自体をオーバーライドして適度なところでクリアかけるとかするしかないかも。