搞定了 NodeJs 程序占内存多的问题
搞定了 NodeJs 程序占内存多的问题
去年转到 node 后发现真香,所有的微服务全都用 node 写了,然后马上发现了一个问题,之前 python 写的程序第 1 天和每 1000 天运行的内存都是一样的,而 node 程序会比较快地增长,直到 boom。
后来发现是因为 node 默认内存限制 1.7G ,而我的小机全是 1G - 2G 的,内存不足。
Google 了一翻,加上命令行选项
–max_old_space_size=600 --max_semi_space_size=8
发现有很大缓解,boom 的次数很少了,但是有另一个问题,就是运行二天后 node 内存就占了 600 - 800M 左右,但是没 Google 到别的解法,就这样将就了一年。
前几天翻 github 时发现另一个解法,在前面选项的基础上再替换默认内存分配器,用 jemalloc。
debian 上是
apt install libjemalloc-dev
然后运行 node 前
export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so.1
我是用 systemd 的,service 文件里加一行
Environment=LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so.1
就行。
然后运行了三天,以前会占用 700M 内存的程序目前稳定在 120M 了,和以前 python 类似。
这个是为啥呢?
你的 node 是什么版本的,是否使用了 buffer,之前听说 node 修复了一个 buffer 导致内存泄露的 BUG
不是,各种版本都一样,目前混用 9 lts 和 10lts
感觉就是不会主动释放空闲内存回 OS,会慢慢占满你指定的 max_old_space_size。
真的很神奇,但你这个是典型的内存泄露,居然可以通过改 jemalloc 化解,真想知道原因
不是内存泄露,我写了好多 node 微服务,全这样,这特么不是我的锅吧
(因为有一个还特简单,不到 100 行,就是转一下图片格式)
另外你 google 一下,小内存机子运行 node 全是这问题, 参考
https://github.com/damianmr/heroku-node-settings
用了五年 Node 了,只有最开始的两年遇到过 Node 内存泄露的问题,当时是定时重启,后来到了 Node6 好像就没有遇到过内存泄漏问题了,阿里云几十台 1 核 2G 的机器,分布式部署一个程序稳定运行数周,内存正常。。。
如果你用 Debian 的目前稳定版的话,我看到 nodejs 包依赖了 libc (其实就是 glibc ):
https://packages.debian.org/stretch/nodejs
或者你用 n、nvm 之类的安装 Node,不清楚是不是会直接用系统内预装的 glibc ?
所以会不会是你装的多数版本的 Node 都是共用的某一个版本的 glibc 提供的内存分配器,而这个版本内存分配器有内存泄漏问题,所以导致不管哪个版本的 Node 都有这个问题。。。实际上你的试验只控制了内存分配器这一个变数,所以基本能得出这个结论。
所以如果有时间可以尝试一下升级系统内的内存分配器动态链接库的版本,看看是不是也能解决这个问题?或者看看默认内存分配器的 issue 或 changelog 是否有提到相关内存泄露问题。
之前加了 max_old_space_size 后内存占用大,但是到那个限制后就不再增加了,程序也不崩,应该不是内存泄漏问题。jemalloc 看一些文章说明它是有缓解内存碎片减少 RSS 的作用。
老哥,说真的,真希望你能研究一下,然后公开一下研究成果。
我手上没你的代码资源和机子的环境,我这边死都复现不了,纠结死了。
你可以看看朴灵写的《深入浅出 nodejs 》,这本书虽然出了都好几年了,但是原理性的内容却是市面上唯一讲到的,里面有专门一节讲述 node 内存的一章,你所提到的内存限制其实都是 v8 对于 js 对象的大小限制,可以多用用 buffer, stream 这些。
为什么我的一直都是 70 多 MB,没出现过你说的几百 M 的
我也一直 600+M,CentOS 7 和 macOS 都是,分别 Node 10 与 12 版本,两个系统都试了下启动 Node 前 export LD_PRELOAD 并指定 jemalloc,内存依旧…会不会是 Node 版本原因
我跟你一样的情况,你问你后面怎么解决的呢?
搞定 Node.js 程序占内存多的问题,通常需要从多个方面入手,包括优化代码、使用高效的库、处理内存泄漏等。以下是一些常见的解决方案和代码示例:
-
优化代码:
- 避免全局变量,尽量使用局部变量。
- 释放不再使用的资源,比如关闭数据库连接、文件句柄等。
-
使用高效的库:
- 选择性能更好的库来处理特定任务,比如使用
stream
处理大文件,避免一次性加载到内存中。
- 选择性能更好的库来处理特定任务,比如使用
-
内存泄漏检测:
- 使用工具如
heapdump
和Chrome DevTools
来分析内存快照,查找内存泄漏。
示例代码:生成内存快照
const heapdump = require('heapdump'); heapdump.writeSnapshot((err, filename) => { if (err) console.error(err); else console.log('Heap snapshot written to', filename); });
- 使用工具如
-
垃圾回收:
- 虽然 Node.js 的垃圾回收机制是自动的,但可以通过一些方法促使垃圾回收,比如设置
--expose-gc
标志并在代码中调用global.gc()
(注意:这通常不推荐在生产环境中使用)。
- 虽然 Node.js 的垃圾回收机制是自动的,但可以通过一些方法促使垃圾回收,比如设置
-
监控和限制内存使用:
- 使用
process.memoryUsage()
监控内存使用情况。 - 通过
child_process
模块将任务拆分成多个子进程,限制每个子进程的内存使用。
- 使用
通过以上方法,通常可以有效降低 Node.js 程序的内存占用。如果问题依然存在,可能需要更深入地分析程序的具体逻辑和使用的第三方库。