🐈
Laravelでcsvを作成するときにAllowed memory size of ~ bytes exhausted エラーが出る時の対処
背景
CSVをスケジューラで作成しておく処理をLaravelで作っていたが、データ量が多くなるにつれ、Allowed memory size of 536870912 bytes exhaustedというエラーが出るようになってしまった。
原因
大量のデータを変数に格納していたこと。
対処法
元々、下記のコードで取得したデータをforeachで回し、1行ずつ書き込んでいた。
$filepath = storage_path('app') . '/filename.csv';
$stream = fopen($filepath, 'w');
$collection = Model::get();
foreach ($collection as $model) {
fputcsv($stream, [
'hoge' => $model->fuga,
'hoge' => $model->fuga,
#
#
#
]);
}
fclose($stream);
下記コードに改修
$filepath = storage_path('app') . '/filename.csv';
$stream = fopen($filepath, 'w');
Model::chunk(200, function ($collection) use ($stream) {
foreach ($collection as $model) {
fputcsv($stream, [
'hoge' => $model->fuga,
'hoge' => $model->fuga,
#
#
#
]);
}
}
fclose($stream);
これで1/4程度に抑えることができました。
おまけ
メモリの調査する際に下記コードがおすすめ
$filepath = storage_path('app') . '/filename.csv';
$stream = fopen($filepath, 'w');
Model::chunk(200, function ($collection) use ($stream) {
foreach ($collection as $counter => $model) {
fputcsv($stream, [
'hoge' => $model->fuga,
'hoge' => $model->fuga,
#
#
#
]);
if ($counter % 1000 === 0) {
print " {$counter}ループ[メモリ使用量]:" . memory_get_usage() / 1024 . "KB\n";
print " {$counter}ループ[メモリ最大使用量]:" . memory_get_peak_usage() / 1024 . "KB\n";
}
}
}
fclose($stream);
print部分はLogに直しても良いと思う。適宜。
Discussion