如何修复Laravel Excel Reader内存泄漏?maatwebsite/excel导入内存过高
内存过高的核心原因
- 错误使用
toCollection方法:Excel::toCollection()的设计逻辑是将Excel内所有符合要求的行最终合并为单个完整集合返回,即便你配置了WithChunkReading分块读取,所有分块的行数据依然会被逐步累加保存在内存中直到读取完成,本质还是全量加载,分块逻辑在这里只负责降低单次读取的峰值,不会减少总内存占用。 ShouldQueue接口未生效:你给Import类加了ShouldQueue,但依然使用同步调用的toCollection方法,队列异步处理逻辑完全没有触发,反而额外增加了对象序列化的开销,进一步拉高内存占用。- 冗余数据被加载:底层依赖的PhpSpreadsheet默认会加载Excel的单元格样式、格式、公式等非数据内容,加上你配置了表头从第15行开始,前面14行的空白/无效内容也会被底层解析加载,额外占用大量内存。
优化方案
1. 替换toCollection为import方法
Excel::import()不会将所有行合并返回,处理完单个分块后会自动释放该分块的内存,不会累计内存占用,调整后调用代码如下:
try { Excel::import( new UsersImport( $entity, $user, $unique_fields, $update_duplicates, new JobHistory, $this->userTypeRepository, ), storage_path().'/uploads/' . $usersFileName ); } catch (\Throwable $th) { throw new Exception($th); }
2. 正确使用队列或移除队列配置
如果需要异步处理导入,将调用方法改为Excel::queueImport(),此时每个分块会作为独立队列任务执行,单任务仅持有当前分块的内存,不会累计。如果不需要异步导入,直接将ShouldQueue接口从Import类中移除,减少不必要的开销。
3. 禁用非必要内容加载
在Import类中添加读取配置,仅加载纯数据,跳过样式、格式、无效行的解析:
可以在config/excel.php中全局配置,也可以在Import类中添加WithReadConcern接口指定只读数据,同时添加读过滤器跳过前14行无效内容,避免冗余数据占用内存。
4. 移除未使用的特性
你当前代码中WithEvents接口的registerEvents返回为空,RemembersChunkOffset特质如果没有用到偏移记录的需求,都可以直接删除,减少对象的内存占用和序列化开销。
5. 手动触发垃圾回收
在collection方法的末尾添加gc_collect_cycles(),强制PHP回收当前分块处理产生的废弃内存,进一步降低内存峰值。
优化完成后,导入800条数据的内存占用会控制在几十MB级别,完全不需要4GB内存。
内容的提问来源于stack exchange,提问作者PHP User
相关产品推荐
相关产品推荐

