前言
这是接着上一篇垃圾回收机制博客的博客。主要讲讲v8引擎新生代老生代的回收算法。
内存大小
32位系统
- 新生代:16MB
- 老生代:0.7G
64位系统
- 新生代:32MB
- 老生代:1.4G
一、新生代回收算法
新生代采用Scavenge垃圾回收算法,Scavenge(清除),在算法实现时主要采用Cheney算法(以空间换时间)。新生代的内存中分为两个半空间,from和to。其中from是用来使用分配空间的,to是空闲的。
算法步骤
- from空间中分配了一些对象,通过GC机制将无法访问的的对象和能访问的活跃对象区分开。
- 将活跃的对象从from空间复制到to空间
- 再将from空间的所有对象全部清除。
- 此时交换from和to空间,让活着的对象任然保存在from空间中,to空间空闲。值得注意的是from和to只是名称交换,但是空间大小没有交换
注意点(晋升)
新生代到老生代的过程就是晋升。
- 如果一个对象经过一次from-to的的Cheney算法(,在第二次Cheney的时候还存活那么会直接放到老生代中。总结来说,如果一个对象是第二次经历从From空间复制到To空间,那么这个对象会被移动到老生代中。
- 从from半空间复制到to半空间的时候,如果这个时候的可用to的空间不足原来的75%,那么这个对象也会晋升到老生代。
- 原因:设置75%的阈值是因为to空间的大小在经历了新生代的清除垃圾回收算法后面会变成from空间的大小,然而from空间会存放很多对象
二、老生代算法
1.标记清除法
老生代采用标记清除法,遍历堆内存中所有对象,标记可访问的对象,清除不可访问的对象。新生代Scavenge算法复制活着的对象,老生代标记-清除法清除死去的对象。这是考虑到新生代中活着的对象少,老生代中死去的对象少。可以这样简便记忆新活少,老活多
2.标记整理法Mark-Compact
由来
Mark-Compact的产生是为了解决标记清除法的问题,什么为问题呢?
假如下图是经历过一次标记清除的内存模拟图,ACE都是活着的对象。
标记清除法清除掉死掉的对象后出现了内存空间不连续的问题。如果有一个对象需要较大的内存但是由于剩余的碎片空间不足以完成此次分配,就会提前触发垃圾回收,而这次回收是不必要的。因此就出现了标记整理法。
算法
- 遍历所有对象,将活着的对象标记。
- 然后将活着的对象往另一边挪动,紧挨着一起,如图ACE
- 然后删除左边所有的对象。
3.两种方法结合
总的来说两种方法各有长处短处,一般采用标记清除法因为他不需要向一侧挪动活着的对象。当内存较大碎片空间不足以完成分配的时候就会使用标记整理法。
推荐阅读
算法具体的伪代码实现,一篇文章推荐阅读
V8 JavaScript引擎研究(三)垃圾回收器的实现