一、概述
垃圾回收机制(GC:Garbage Collection),执行环境负责管理代码执行过程中使用的内存。
垃圾收集器会定期(周期性)
找出那些不在继续使用的变量,然后释放其内存。
但是这个过程不是实时的,因为其开销比较大,所以垃圾回收器会按照固定的时间间隔周期性的执行
调用栈中的数据如何回收
在调用栈中,有一个记录当前执行状态的指针(ESP)
,通过栈中下移指针完成已执行完成的函数的执行上下文
的销毁,
新函数执行,新函数的执行上下文入栈,直接覆盖内存。
引用数据(堆)中的数据如何回收
代际假说
代际假说(The Generational Hypothesis)
1、大部分对象在内存中存在的时间很短;
2、不死的对象,会活得更久;
分代收集
现在V8浏览器会把堆分为新生代和老生代两个区域
新生代中存放的是生存时间短的对象,老生代中存放的生存时间久的对象
新生代 - 副垃圾回收器
一般新创建的对象都在新生代中,新生代中用Scavenge 算法
来处理
把新生代空间对半划分为两个区域,一半是对象区域,一半是空闲区域
新加入的对象都会放到对象区域,当对象区域快被写满时,就执行一次垃圾清理操作。
在垃圾回收过程中,首先要对对象区域中的垃圾做标记;标记完成之后,就进入垃圾清理阶
段,副垃圾回收器会把这些存活的对象复制到空闲区域中,同时它还会把这些对象有序地排
列起来,所以这个复制过程,也就相当于完成了内存整理操作,复制后空闲区域就没有内存
碎片了
老生代 - 主垃圾回收器
在新生代中一般存活超过两次垃圾回收机制的对象会晋升到老生代。除此之外,一些大的对象会直
接被分配到老生区。主垃圾回收器是采用标记 - 清除(Mark-Sweep)的算法进行垃圾回收的
首先是标记过程阶段。标记阶段就是从一组根元素开始,递归遍历这组根元素,在这个遍历
过程中,能到达的元素称为活动对象,没有到达的元素就可以判断为垃圾数据。
标记 - 整理(Mark-Compact)
因为标记 - 清除容易产生大量内存碎片,所以对此优化出标记 - 整理(Mark-Compact)
标记过程仍然与标记 - 清除算法里的是一样的,但后续步骤不是直接对可回收对象进行清理,而是让所
有存活的对象都向一端移动,然后直接清理掉端边界以外的内存
增量标记(Incremental Marking)
如果有很多对象,并且我们试图一次遍历并标记整个对象集,那么可能会花费一些时间,并在执行中会有一定的延迟。
因此,引擎试图将垃圾回收分解为多个部分。然后,各个部分分别执行。这需要额外的标记来跟踪变化,这样有很多微小的延迟,而不是很大的延迟。
总结
不论什么类型的垃圾回收器,它们都有一套共同的执行流程,只是表现形式不一样
- 标记空间中活动对象和非活动对象。所谓活动对象就是还在使用的对象,非活动对象就是可以进行垃圾回收的对象
- 回收非活动对象所占据的内存
- 内存整理。也就是将回收后的内存碎片进行整理。新生代在复制过程中完成,老生代为此还会再一次遍历堆进行移动整理
参考资料
浏览器工作原理与实践 - 李兵