栈的内存空间是自动分配的,它由系统自动释放,堆的内存空间是动态分配的,大小不定,不会自动释放,需要 JS 引擎释放这些内存。v8 采用的分代式垃圾回收机制。
分代式垃圾回收机制
v8 堆内存结构包含新生代内存区,老生代内存区,大对象区,Map 区,代码区。垃圾回收发生在新生代内存区和老生代内存区。
从根(window,global)开始,找所有从根开始引用的对象,然后找这些对象引用的对象……,一直递归,被找到的对象就是活动对象,从根往下找不到的对象就是未活动对象,可以被回收。
新生代
存储空间小,垃圾回收频繁
- 新生代空间分为半个 From 空间,半个 To 空间
- 声明的对象首先分配到 From 空间。
- 垃圾回收时,复制 From 空间的活动对象到 To 空间。留在From空间的非活动对象会被自动回收
- 复制完成后,From 空间和 To 空间完成互换。To 空间变成新的 From 空间,From 空间变成新的 To 空间。
老生代
存储空间大,存放存活时间较久的对象
- 新生代的对象经过多次复制后依旧存活(至少经历过一次复制,且新生代 To 空间的内存占比超过了 25%),在下一次进行垃圾回收时,该对象直接转移到老生代中。
- 遍历堆中所有的对象,标记活动对象,清除未活动对象。
- 对象清除后,在整理的过程中,会将活动的对象往堆内存的一端进行移动。(碎片整理,方便存放较大的对象)
- 可以标记或者整理一部分对象,然后暂停,将执行权交给 js 主线程,待主线程空闲时再从原来标记的地方继续标记或者整理。(不影响主线程运行)
- 也可以利用增量标记、懒性清理、并发、并行来减少主线程挂起的时间。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。