垃圾回收简称GC(Garbage Collection)
js中,基础数据类型存储在栈内存中,引用数据类型存储在堆内存中,不同的内存有不同的垃圾回收机制。
栈和堆的区别
栈(stack)内存由系统自动分配固定的内存空间,遵循先进后出原则。
特点:线性有序存储,容量小,分配效率高。
堆(heap)内存由系统动态分配不固定的内存空间,不会自动释放。
特点:无序的树状结构,容量大,分配效率底。(因为先开辟空间,再将堆地址存入栈内存中)
栈内存的GC
栈内存就是执行栈,执行栈存储的是执行上下文。
每执行一个函数,函数的执行上下文会被压入栈中。
栈内存有个记录当前执行状态的指针ESP,指向调用栈中正在执行的函数的执行上下文。
当函数执行完毕后,ESP指针下移,函数的执行上下文就会出栈。
堆内存的GC
堆内存的垃圾回收机制用的是V8的垃圾回收器进行内存回收。
V8采用的是分代式垃圾回收机制。
分代是指将堆内存分为新生代和老生代,新生代中的对象为存活时间较短的对象,老生代中的对象为存活时间较长或长驻内存的对象。
| 新生代 | 老生代 |
|---|
新生代
新生代主要采用scavenge算法进行垃圾回收,而scavenge算法具体实现采用的是cheney算法。
cheney算法是一种采用复制的方式进行垃圾回收。该算法将堆内存一分为二,每个空间称为semispace,一个semispace处在使用状态为From空间,一个semispace处在闲置状态为To空间。
分配对象时,先分配在From空间。垃圾回收时,会检查From空间中的存活对象,将存活对象复制到To空间中,完成复制后,From空间和To空间角色发生转换。没有被复制的非存活对象将被释放。
| semispace(From) | semispace(To) | 老生代 |
|---|
scavenge的缺点:只能使用堆内存的一半。
老生代
老生代采用标记清除(Mark-Sweep)和标记整理(Mark-Compact)结合的方式进行垃圾回收。
Mark-Sweep分为两个阶段,标记阶段:遍历堆中的对象,并标记存活对象;清除阶段:清除没有标记的对象。
每次Mark-Sweep后会存在内存碎片,所以有了Mark-Compact。
Mark-Compact是Mark-Sweep演变而来,区别是标记存活对象后,将存活的对象移到一端,而后清除另一端。
新生代晋升老生代
晋升条件:
- 该对象是否经历过scavenge回收
- To空间占比超过25%