You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel API导出CSV触发Symfony内存耗尽错误求助

问题原因分析
  1. 大字符串内存累积:重构后通过$csv_file_contents .= ...持续拼接字符串,PHP中字符串属于不可变类型,每次拼接都会生成新的字符串实例,旧实例需等待下一次垃圾回收(GC)才能释放。6000条记录的CSV内容会占用大量内存,拆分方法后可能延长了大字符串的生命周期,导致内存无法及时回收。
  2. 模型集合引用泄漏:拆分后的子方法如果持有整个查询到的模型集合引用,会阻止PHP垃圾回收器回收这些模型对象。原来的单方法中,局部变量可能在执行完部分逻辑后就被标记为可回收,而多方法结构下集合可能被多个方法引用,长期驻留内存。
  3. 隐式重复数据加载:如果子方法内部存在重复查询或模型属性的懒加载行为,会额外加载更多数据到内存中,进一步加剧内存消耗。
解决方案

1. 流式写入文件,避免内存拼接

不要在内存中累积整个CSV内容,直接用文件句柄逐行写入,从根源减少内存占用:

$handle = fopen(storage_path('app/temp_contracts.csv'), 'w');
// 写入CSV表头
fputcsv($handle, ['合同ID', '合同名称', '总金额', '税费']);

// 用cursor()迭代模型,每次仅加载单个模型到内存
Contract::query()->cursor()->each(function ($contract) use ($handle) {
    // 生成当前行的CSV数据
    $row = $this->buildCsvRowForContract($contract);
    fputcsv($handle, $row);
    // 手动销毁模型对象,释放内存
    unset($contract);
});

fclose($handle);

// 返回文件给前端,发送后自动删除临时文件
return response()->download(storage_path('app/temp_contracts.csv'))->deleteFileAfterSend(true);

2. 移除不必要的集合引用

如果必须保留多方法结构,不要传递整个模型集合,改为逐行传递单个模型或仅需的属性:

// 错误方式:传递整个集合
$this->updateCsvWithFinancialSummariesForContractDetails($contracts, $csv_content);

// 正确方式:逐行处理,传递单个模型
foreach ($contracts as $contract) {
    $csvLine = $this->buildFinancialSummaryLine($contract);
    fwrite($handle, $csvLine . PHP_EOL);
    unset($contract);
}

3. 强制触发垃圾回收

在批次处理的间隙手动触发GC,主动回收未被引用的对象:

$batchSize = 100;
Contract::query()->chunk($batchSize, function ($contracts) use ($handle) {
    foreach ($contracts as $contract) {
        fputcsv($handle, $this->buildCsvRowForContract($contract));
    }
    // 销毁当前批次的集合
    unset($contracts);
    // 强制回收内存
    gc_collect_cycles();
});

4. 优化模型查询,减少内存占用

只查询需要的字段,关闭不必要的懒加载,避免加载冗余数据:

Contract::query()
    ->select('id', 'name', 'total_amount') // 仅选择需要的字段
    ->with(['financial_summary' => function ($query) {
        $query->select('contract_id', 'tax', 'discount'); // 预加载关联时仅取必要字段
    }])
    ->cursor()
    ->each(function ($contract) use ($handle) {
        // ...处理逻辑
    });

5. 确认内存配置生效

虽然你设置了memory_limit=-1,需确认当前运行环境使用的是对应配置文件:

  • CLI环境执行php -i | grep memory_limit查看生效配置
  • Web环境通过phpinfo()页面确认当前memory_limit值

内容的提问来源于stack exchange,提问作者Drew Gallagher

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 23:07:55