Node.js应用spawn ENOMEM内存错误的临时方案咨询
运行Node.js应用时触发的spawn ENOMEM错误为系统内存不足导致,错误栈如下:
Error: spawn ENOMEM at ChildProcess.spawn (internal/child_process.js:406:11) at spawn (child_process.js:553:9) at Object.execFile (child_process.js:237:17) at exec (child_process.js:158:25) at CheckIP (/(PATH)/(APPNAME)/app.js:57:3) at Layer.handle [as handle_request] (/(PATH)/(APPNAME)/node_modules/express/lib/router/layer.js:95:5) at trim_prefix (/(PATH)/(APPNAME)/node_modules/express/lib/router/index.js:317:13) at /(PATH)/(APPNAME)/node_modules/express/lib/router/index.js:284:7 at Function.process_params (/(PATH)/(APPNAME)/node_modules/express/lib/router/index.js:335:12) at next (/(PATH)/(APPNAME)/node_modules/express/lib/router/index.js:275:10) at cookieParser (/(PATH)/(APPNAME)/node_modules/cookie-parser/index.js:71:5) at Layer.handle [as handle_request] (/(PATH)/(APPNAME)/node_modules/express/lib/router/layer.js:95:5) at trim_prefix (/(PATH)/(APPNAME)/node_modules/express/lib/router/index.js:317:13) at /(PATH)/(APPNAME)/node_modules/express/lib/router/index.js:284:7 at Function.process_params (/(PATH)/(APPNAME)/node_modules/express/lib/router/index.js:335:12) at next (/(PATH)/(APPNAME)/node_modules/express/lib/router/index.js:275:10)
该错误触发逻辑为:CheckIP接口处理请求时调用exec创建子进程,系统无足够内存资源分配给新进程,直接抛出错误。以下是两个问题的落地解决方案:
错误触发时自动重启应用的实现
完全可以实现,优先用systemd原生能力,稳定性远高于自定义脚本:
- 修改对应服务的systemd配置文件,默认路径为
/etc/systemd/system/APPNAME.service,在[Service]段追加以下配置:
[Service] # 保留原有配置项 Restart=on-failure RestartSec=3 # 配置应用最大内存阈值,超过阈值自动重启,提前规避ENOMEM MemoryMax=1G
- 执行命令重载配置生效:
systemctl daemon-reload && systemctl restart APPNAME
如果应用触发ENOMEM后没有直接退出,只是接口返回错误,systemd原生重启规则不会生效,此时需要用日志监控脚本做精准触发:
- 新建脚本文件
/opt/enomem_monitor.sh,写入以下内容:
#!/bin/bash journalctl -u APPNAME.service -f --since "now" | while read -r log_line; do if echo "$log_line" | grep -Fq "spawn ENOMEM"; then echo "$(date '+%Y-%m-%d %H:%M:%S') 检测到ENOMEM错误,执行服务重启" >> /var/log/app_monitor.log systemctl stop APPNAME sleep 2 systemctl start APPNAME fi done
- 给脚本加执行权限:
chmod +x /opt/enomem_monitor.sh - 将脚本配置为systemd服务设置开机自启即可,不需要额外的轮询开销。
内存不足问题的临时缓解方案
确认是内存问题导致的错误,可以通过以下配置/脚本缓解:
- 配置Swap分区:这是见效最快的方案,可在物理内存不足时借用磁盘空间作为虚拟内存,避免子进程创建直接失败。
- 先执行
free -h查看当前Swap配置,若Swap行总大小为0,按以下步骤创建4G大小的Swap(大小可根据服务器磁盘情况调整,一般为物理内存的1~2倍):
fallocate -l 4G /swapfile chmod 600 /swapfile mkswap /swapfile swapon /swapfile echo '/swapfile none swap sw 0 0' >> /etc/fstab- 调整swappiness参数降低Swap使用优先级,避免过早使用磁盘虚拟内存导致应用性能下降,建议设置为10~30:
echo 'vm.swappiness=20' >> /etc/sysctl.conf sysctl -p - 先执行
- 定时清理系统缓存:配置crontab定时任务,每2小时清理一次系统页缓存、目录项和inodes缓存,释放被缓存占用的内存:
执行crontab -e追加以下内容:0 */2 * * * sync && echo 3 > /proc/sys/vm/drop_caches - 限制Node.js应用内存上限:启动Node.js时添加
--max-old-space-size参数限制堆内存大小,预留足够内存给子进程创建使用,比如限制最大堆内存为800M:node --max-old-space-size=800 app.js - 优化子进程调用逻辑:如果条件允许,将
CheckIP逻辑中每次请求都exec创建子进程的实现,改为用Node.js原生模块实现对应功能,从根源减少fork子进程的内存开销。
注意:以上方案均为临时止损手段,后续仍需排查应用是否存在内存泄漏、接口并发过高导致短时间创建大量子进程等根因,完成彻底修复。
内容的提问来源于stack exchange,提问作者Russell Harrower
相关产品推荐
相关产品推荐

