V8内存处理逻辑

V8内存机制

  • 常规而言,64位系统可用内存为1.4G,32位为0.7G,以 1.5 GB 的垃圾回收堆内存为例,最快也要 50毫秒,全量GC 需要 1 秒以上

内存组成

  • 分代式垃圾回收机制

内存分为新生代的内存空间和老生带的内存空间

新生代内存空间

  • 设置指令: node --max-new-space-size // 默认1024 KB
  • 64位系统为32MB 32位系统16M

Scavenga 算法

  • 将内存分为 from 和 to , 先将对象分配在 from 中,在进行垃圾回收的时候,将存活的对象,从 form 复制到 to 中(如果to空间占用已经超过 25% ,则直接进入老生带内存空间),复制完之后,释放 from 。同时 to 空间作为下一个 from 空间。每一个已经从 from->to 空间的对象,再下一次GC之后,如果已经经历过 Scavenga 算法,将进入老生带内存空间而非 to 空间

老生代内存空间

  • 设置指令: node --max-old-space-size // 默认1700 MB
  • 经历过 Scavenga 算法的对象,通常是活对象居多,每次只需要清除少量的死对象。

Mark-Sweep & Mark-Compact 算法

Mark-Sweep 标记清除

  • 进行一次标记清楚回收之后,内存空间会出现不连续的状态,这种内存碎片会对后续的内存分配造成问题,因为很可能出现需要分配一个大对象的情况,这时所有的碎片空间都无法完成此次分配,就触发没必要垃圾回收。因此,Mark-Compact 算法被提出来。

Mark-Compact 标记整理

在空间不足以对新生代晋升过来的对象进行分配时,才使用 Mark-Compact

  • 对象再标记死亡之后,在整理的过程中,将活着的对象往一端移动,移动完成后,直接清理掉边界外的内存

Incremental Marking 增量标记

为了降低全堆垃圾回收带来的停顿,V8 先从标记阶段入手,将原本要一口气停顿完成的动作改为增量标记,也就是拆分为许多小“步进”,没做完一“进步”,就让 js 应用逻辑执行一小会儿,垃圾回收和应用逻辑交替执行直到标记阶段完成。

lazy-sweeping 延迟清理

increamental-compaction 增量式整理

并行标记

并行清理

Buffer

  • Buffer对象的内存分配不是在V8的堆内存中,而是在Node的C++层面实现内存的申请。
  • 因为在处理大量的字节数据,不能采用需要一点内存就向操作系统申请一点内存的方式,这可能造成大量的内存申请的系统调用,对操作系统有一定压力。

slab 分配机制

createReadStream 使用用例

var fs=require('fs')
var rs =fs.createReadStream('GC.md') // 注释1 {highWaterMark:11}
// 注释2 rs.setEncoding('utf8')
var d =''
rs.on('data',(e)=>{
    d+=e
})
rs.on('end',()=>{
    console.log(d)
})
复制代码

d+=e => d=d.toString()+e.toString()

如果打开注释的内容,将会出现 ❓

  • 原因是,文件读取时一部分一部分读,如果中途折断了,原先属于那个字符的字节,将会被划分到下一个流中读取,原先的字节就丢失了,造成解码失败。
  • 处理截断的话,本质是用的 decoder 对象,将之前截断的部分存下来,与下一个流进行拼接。目前只能完成utf-8,base64,ucs-2/utf-16lf 三者中编码。

转载于:https://juejin.im/post/5d06eebef265da1b8b2b5de1

猜你喜欢

转载自blog.csdn.net/weixin_33841722/article/details/93171318
v8