Node内存限制与解决方案
什么是node内存,为什么需要内存限制
- 在32位系统限制 0.7GB
- 64位系统限制 1.4GB
导致的问题:
Node 无法直接操作大文件对象。
例如我想读取一个 4g 的文件来处理,即使物理内存有 32GB,在单个 Node 进程中也是不能完全的使用的。
我们平常在声明一些对象的时候,要是没有Node垃圾回收机制回收 ,就会占用V8限制的内存
为什么有内存限制
内存限制主要原因是v8的垃圾回收制度。1.5GB内存做一次小的回收需要50MS,做一次非增量性回收需要1S以上,并且这会使JS线程暂停。因此限制内存。
如何查看目前使用多少内存
所有的 JS 对象都是通过堆来进行分配的。
process.memoryUsage()
> node
> process.memoryUsage()
{
rss: 21917696, // rss (resident set size) 进程的常驻内存
heapTotal: 7684096, // 已申请到的堆内存
heapUsed: 5147296, // 当前使用的堆内存
external: 8655
}
// 以上单位 字节
如何解决内存限制
可以使用Buffuer,因为Buffer不受V8的内存分配机制,
1.修改内存限制大小
node --max-old-space-size=1700 test.js // 单位为MB
node --max-new-space-size=1024 test.js // 单位为KB
2.高效使用内存
- 少用全局作用域,全局作用域的变量要等程序退出,才释放,建议使用null或undefined主动释放
在某个局部作用域中的对象会随着局部作用域的销毁而被释放,在下次垃圾回收的时候就会清理掉这部分内存,如果全局作用域中的对象过多,那么这些对象存在的作用域直到继承退出才会被释放,这些对象也会最终停留在老生代内存区域中。
如果你想手动释放一个变量,可以使用delete操作符,但是并不推荐这样做,这样做会干扰V8引擎的优化,推荐使用将对象赋值为null或undefined来手动释放它。
3.使用非V8引擎内存
Node.js程序所使用的内存分为两类:
-
V8内存
:数组、字符串等JavaScript
内置对象,运行时使用“V8内存” -
系统内存
:Buffer
是一个Node.js的扩展对象,使用底层的系统内存,不占用V8
内存空间。与之相关的文件系统fs
和流Stream
流操作,都不会占用V8
内存。
在程序允许的情况下,应该将数据保存在Buffer
中,而不是转换成字符串等JS对象,这样可以避免V8
内存的过多占用。
4.使用process.nextTick()
防止事件堆积
process.nextTick()会在本次事件循环结束后,立即开始下次事件循环。这样可以使V8获得内存回收的机会,有效解决过多事件堆积造成的内存溢出。
我们可以使用process.nextTick()方法处理:
forLoops(0);
function forLoops(i) {
if(i<10000000)
{
var site = {};
site.name = '内存';
site.domain = 'nodejs.com';
// 这里是一个保存或更新等操作
setTimeout(()=>{
console.log(i, site);
}, 0)
process.nextTick(forLoops, i+=1);
}
}
每次循环V8都会回收内存一次,因此内存不会再溢出。但这样做必然会造成运行效率的降低,而应该在速度在安全之间平衡,控制好循环的安全次数。
5.拆分进程
官方建议:it is recommended that you split your single process into several workers if you are hitting memory limits. (拆分进程)