美文网首页
2020-08-28-Node内存控制

2020-08-28-Node内存控制

作者: 宇宙区长李小无 | 来源:发表于2020-08-28 18:24 被阅读0次

    V8内存

    V8内部的内存对象分为新生代和老生代,新生代是代表存在时间较短,很快被释放内存空间的对象,而老生代对象则是常驻在Node进程中,
    只有进程结束才会被销毁。

    一般来说V8对新老生代对象的内存分配是固定的,根据设备的64位(old: 1400MB,new: 4*16MB)或者32位(减半)分配对应的内存。
    但是我们也可以在node进程启动的时候主动去分配。

    node --max-old-space-size=1700 test.js // 单位为MB
    node --max-new-space-size=1024 test.js // 单位为KB 
    

    垃圾回收机制:

    分代式垃圾回收

    • scavenge算法(复制剔除大法)

      主要针对新生代对象的垃圾回收,它会将新生代分配的内存拆分为两份(from-to),新晋的新生代对象分配到from区,当进行垃圾回收的
      时候,会将from区的对象复制到to区,在这个过程中,判断出可以销毁的变量对象,直接释放对应的内存,然后再将to区的对象还原到from区,
      等待下次回收。

      这个算法相当于只能利用一半的内存,但是速度非常快,典型的空间换时间,空间还是比较宝贵的,所以
      scavenge算法只适合用于新生代小对象的回收。

    • 晋升

      在经历过scavenge处理多次后,仍然处于存活状态的对象,就会被移动到老生代中,采用新的算法进行管理。

      触发条件:

      1、经过scavenge回收;

      根据对象的内存地址来判断是否进行过scavenge回收,有,则进入老生代空间。

      2、To空间内存占用超过限制(新生代内存分配较少)。

      在复制到To空间的过程中判断To空间的使用率是否超过25%,是,则进入老生代空间。
      之所以限制25%,因为回收完毕后,To空间会与From空间进行互换,如果占比过高,会影响From空间的新的内存分配。

    • mark-sweep算法(标记清除大法)

      对于老生代对象,大部分对象的存活期是比较长的,频繁的进行复制操作,非常耗时,所以采用mark-sweep算法来进行老生代对象的回收,
      它遍历整个堆中的对象,标记出存活和死亡的对象,然后将死亡的对象内存空间直接释放。

      该算法的问题是回收完毕后,会出现内存空间不连续,产生内存碎片,影响后续大对象的内存分配。

    • mark-compact(标记清除再聚拢)

      mark-sweep的衍生版本,在清除死对象的时候,将存活对象向一端移动,避免产生内存碎片。

    算法          scavenge        mark-sweep      mark-compact
    ---------------------------------------------------------
    空间开销    双倍空间(无碎片)    少(有碎片)      少(无碎片)
    速度          极快              中等              最慢
    是否移动对象    是                否                是
    

    内存溢出

    通常来说内存溢出的原因有:

    • 作用域未被及时释放(闭包、过多的全局变量等)
    • 缓存(未设置过期时间)
    • 队列消费不及时(定时器或异步操作导致事件队列堆积了过多的任务)

    大文件操作

    由于V8内部对内存大小有限制,所以在读取一些超大文件时,我们无法通过fs模块,而需要使用Stream流,它分为可读、可写流,
    含有pipe方法,对文件流进行操作,不会受到内存的影响。

    var reader = fs.createReadStream('a.txt');
    var writer = fs.createWriteStream('b.txt');
    reader.pipe(writer);
    

    相关文章

      网友评论

          本文标题:2020-08-28-Node内存控制

          本文链接:https://www.haomeiwen.com/subject/lhxrsktx.html