大き過ぎるXMLファイルをPHPのバッチで解析する

やりたいこと

WebAPI リクエストで得られる XML ファイルを解析する。PHPXML を解析するならば、XML_Unserializer を使えば簡単なわけです。今回、データが大き過ぎるXMLファイルを解析したい、それも、バッチで一括処理したい、という用があって、困ってしまった。

問題点

memory_limit を 500MB まで上げた状態でも、メモリが足りないという実行時エラーになってしまう。一般に、パーサを通すと元ファイルの4倍くらいのメモリを食う。

基礎知識

  • 組み込み関数 memory_get_usage でデバッグログすることで、メモリの使用状況を把握し、食っている箇所を突き止める。
  • gc を促すには unset という手段があります。とはいえ、これは実行環境依存なので、unset しても解放されないケースはある。XML_Unserializer の場合、unset が効かないというか、パーサライブラリ内部の方でリークしているのではないか、と思われる挙動だった。
    • PHP5のgcはリファレンスカウンタらしいので、循環参照があるとリークする。
  • 省メモリなライブラリとして XMLReader というパーサもあるけれど、こちらはプログラムがしんどくなりそう。

対処した方法

メモリ管理をPHPではなくOSにしてもらう方式にしたら、メモリ問題は回避できた。元データであるXMLを一括ダウンロードする(1ファイル)のではなく、リクエストを分割して(複数ファイル)で取得する。system 関数を使ってリクエスト毎(取得したファイル毎)に毎回プロセス起動させることにした。

下記を参考にさせてもらいました。