PhpSpreadsheetが複数ファイルをループするとメモリを使いすぎる
PhpSpreadsheetでxlsxファイルを処理しているときにメモリエラーが出たので調査したときの覚書。
環境: Windows 11 pro, PHP 8.3.13, PhpSpreadsheet 3.5.0
数メガある10個ほどのxlsxファイルをループ処理したら下記エラー。
PHP Fatal error: Allowed memory size of 1073741824 bytes exhausted (tried to allocate 4096 bytes) in D:/../
次のファイルを読み込むごとにメモリ消費が増えていく。
PhpSpreadsheetはIteratorを使ってメモリ消費を最小限にしているはず。
参考: Looping the Loop - PhpSpreadsheet Documentation
試したこと
- php.iniのmemory_limitを1024Mにした。
- Loop中にmemory_get_usage()を出力して、どこでメモリ消費するか計測。
xlsxをload前にsetReadDataOnly(true)する。
→ 変わらなかった。Loopの最後で変数をunsetする。
→ 変わらなかった。
10,000行の1MBのxlsxファイルをloadするとメモリ126MBを消費した。
memory_limit=1024Mだと8MB(約80,000行)のファイルを処理するのが限界。
フォルダに置いたxlsxファイルをループして処理したかったけど、メモリの使い過ぎで止まってしまうので別の方法を考える。
対策案
- 一つずつ別スレッドで処理(1つのPHPコマンドで1ファイル処理)。
- 一旦XLSXをCSVに変換してから処理。
- 一時的にクラウドのハイスペックマシンで処理。
- そもそもPhpSpreadsheetを使わず、Power AutomateでXLSXをCSVに変換してから処理。
CSVファイルをfgetcsvでループ処理する際はファイルサイズに関わらず使用メモリは増えないので、一旦何らかの方法でXLSXをCSVに変換するのが有力候補。