Node.js使用excelJS导出Excel触发堆内存溢出(错误码137)问题求助
Node.js服务端生成Excel堆内存溢出解决方案
直接原因排查
首先你的启动参数配置错误,max_old_space_size 参数前需要加两个短横线,你当前使用的单横线参数未生效,Node还是使用默认内存上限,这是你配置了20G内存依然报137错误的核心原因:
# 错误写法 node -max_old_space_size=20480 server.js # 正确写法 node --max-old-space-size=20480 server.js
核心逻辑优化(内存占用降低90%+)
你当前的最大性能损耗来自于readAndWrite的逻辑:每追加一页数据就把整个Excel文件全部读取到内存中重新写入,40页数据就会触发39次全量文件读/写,越到后续内存占用越高。优化方案如下:
方案1:全量处理完一次性写入
仅初始化一次Workbook实例,每拿到一页数据直接追加到内存中的工作表,全部页处理完成后再一次性写入磁盘:
const workbook = new excel.Workbook(); const worksheet = workbook.addWorksheet("My Sheet"); worksheet.columns = columns; // 你的分页数据,注意修复原代码的循环变量笔误:原代码for循环传参错误把p传给了getData const pageNumbers = Array.from({length:40}, (_,i)=>i+1); for (const page of pageNumbers) { const data = await getData(page, limit, organization_id, token, baseurl, sideFilter); worksheet.addRows(data); // 用完的变量置空,方便垃圾回收 data = null; // 每处理10页可主动触发GC,需启动时加--expose-gc参数 if(page % 10 === 0) global.gc?.(); } // 全部处理完成后一次性写入文件 await workbook.xlsx.writeFile('./export.xlsx'); console.log("导出完成");
方案2:超大文件场景用流式写入
如果单文件数据量超过10万行,直接用exceljs的流式写入API,无需将整个Workbook保存在内存中:
const options = { filename: './export.xlsx', useStyles: false, useSharedStrings: false }; const workbook = new excel.stream.xlsx.WorkbookWriter(options); const worksheet = workbook.addWorksheet('My Sheet'); worksheet.columns = columns; for (const page of pageNumbers) { const data = await getData(page, limit, organization_id, token, baseurl, sideFilter); // 逐行写入流 for(const row of data) { worksheet.addRow(row).commit(); } data = null; } // 提交写入完成 await workbook.commit();
内存泄漏修复
- 去掉
getData中多余的new Promise包装:axios本身返回Promise,额外包装会产生冗余闭包持有变量,导致垃圾回收无法正常释放内存 - 原代码中的
delete newWorkbook操作无效:JS垃圾回收自动管理,手动delete不会立即触发内存释放,将用完的大变量置为null即可 - 简化可选链写法:将多层
a?a.b:'--'替换为a?.b ?? '--',减少重复变量引用
内容的提问来源于stack exchange,提问作者hu7sy
相关产品推荐
相关产品推荐

