Node内存限制与解决方案

2020-03-23  本文已影响0人  夏夏夏夏顿天

什么是node内存,为什么需要内存限制

导致的问题: 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.高效使用内存

在某个局部作用域中的对象会随着局部作用域的销毁而被释放,在下次垃圾回收的时候就会清理掉这部分内存,如果全局作用域中的对象过多,那么这些对象存在的作用域直到继承退出才会被释放,这些对象也会最终停留在老生代内存区域中。
如果你想手动释放一个变量,可以使用delete操作符,但是并不推荐这样做,这样做会干扰V8引擎的优化,推荐使用将对象赋值为null或undefined来手动释放它。

3.使用非V8引擎内存

Node.js程序所使用的内存分为两类:

在程序允许的情况下,应该将数据保存在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. (拆分进程)


上一篇下一篇

猜你喜欢

热点阅读