概要
- phpoffice/phpspreadsheetでは明示的に解放しないとメモリを確保しつづけるようで、特に複数のファイルを一括してバッチ処理するような場合にはメモリ使用量が急増する。
- 関数の中でローカル変数として生成したインスタンスでもメモリは解放されない。
- 解放は
disconnectWorksheets()
してからgarbageCollect()
環境
- CentOS 7.6
- PHP 7.3.5
- phpoffice/phpspreadsheet 1.6.0
- テストに用いたExcelファイル https://www.mhlw.go.jp/topics/2018/04/tp20180401-01.html から、tp20180314-01_05.xls
コードで比較
A列を全行読み出すだけの関数
function without_disconnect($xls_file) {
$xreader = new PhpOffice\PhpSpreadsheet\Reader\Xls();
$xls = $xreader->load($xls_file);
$sheet = $xls->getSheet(0);
foreach ($sheet->getRowIterator() as $row) {
$val = $sheet->getCell("A".$row->getRowIndex())->getValue();
}
}
読み出した後に解放する関数 (2行追加)
function with_disconnect($xls_file) {
$xreader = new PhpOffice\PhpSpreadsheet\Reader\Xls();
$xls = $xreader->load($xls_file);
$sheet = $xls->getSheet(0);
foreach ($sheet->getRowIterator() as $row) {
$val = $sheet->getCell("A".$row->getRowIndex())->getValue();
}
$xls->disconnectWorksheets();// 追加
$xls->garbageCollect();// 追加
}
実行して比較
上記の2つの関数を3回ずつ呼んで、メモリ使用量を出力する。
メモリ使用量を出力する関数
function echo_mem($prefix='') {
print($prefix.':');
print(floor(memory_get_usage() / 1024).'KB'.PHP_EOL);
}
解放しない
without_disconnect
$f = __DIR__.'/tp20180314-01_05.xls';
echo_mem('before');
for ($i = 0; $i < 3; $i++) {
without_disconnect($f);
echo_mem('without'.$i);
}
結果
before:654KB
without0:53921KB
without1:103656KB
without2:156463KB
解放する
with_disconnect
$f = __DIR__.'/tp20180314-01_05.xls';
echo_mem('before');
for ($i = 0; $i < 3; $i++) {
with_disconnect($f);
echo_mem('with'.$i);
}
結果
before:654KB
with0:14973KB
with1:14973KB
with2:14973KB
追記2019-05-26 他のシートを開きたい時は解放してはいけない
disconnectWorksheets()
した後で別のシートを開こうとしてもnull
が返る。
// 1つ目のシートを開く
$sheet = $xls->getSheet(0);
/* 何か処理 */
$xls->disconnectWorksheets();
// 2つ目のシートを開きたい
$sheet = $xls->getSheet(1);
var_dump($sheet); // NULL