PHPはリファレンスカウントGCを使っているというお話

バイト先でHyper Estraierを使った全文検索機能を実装する機会がありました。

そこで、EstraierPureライブラリを使って、PHPスクリプトを通じてHyper Estraierにテキストのインデックスを作成させるようにしたのですが、複数のテキストファイルをインデックス化する途中で下記PHPエラーが出てPHPプロセスが終了しました。

PHP Fatal error: Allowed memory size of 8388608 bytes exhausted (tried to allocate 22423 bytes) in /var/lib/Services/HyperEstraier/Utility.php on line 278

なんかメモリが足りなくなっとるらしい。

また、インデックス化に失敗したテキストファイルから実行再開すると、そのテキストのインデックス化に成功した後、別のテキストファイルをインデックス化する時に同様のエラーが出てプロセスが終了します。

以上の結果からメモリリークの疑いが強いのですが、EstraierPureは100%PHPコードなので、PHPのメモリ管理に原因がありそうです。

ということで、PHPのメモリ管理方法を調べてみたところ、リファレンスカウント方式のGCだと判明しました*1。今までTracing GC系だと思ってたよ・・・

現在、PHPのリファレンスカウントGCは循環参照しているオブジェクトは解放できません。おそらく、EstraierPureの中で循環参照があって、そのオブジェクトが解放されずにリークし、最終的にメモリが足りなくなるのでしょう。

PHP6からは、Pythonでも使われているCycle Collector*2が実装されるそうなので*3、今回の問題もPHP6を使えば解消します。

ってまだPHP6は正式リリースされてないし、今更PHP5から変えられるかーっていう状況。PHP5.3でもCycle Collectorが導入されるといいなあ。・・・結局リリース待ちなわけだけど。