V8 内部的内存分配如下图所示:因为 V8 是基于分代的垃圾回收机制,所以在 V8 的内部在内存空间分成了两个部分就像图中显示的这样。内部的一个存储区域被分成了左侧的白色区域,和右侧的偏红色的区域。左侧就是专门又来存储新生代对象,右侧就是专门用于存放老生代对象。在这里我们当前只是关注一下新生代存储区的垃圾回收操作,所以在这我们先做一些文字上的说明。跟刚才看到的一样,我们当前的 V8 内部是吧空间分成了两部分,而左侧专门去用于存储新生代对象。这样的一个空间是有一定设置的,在 64位操作系统当中它的大小是 32M、在 32位操作系统中就是 16M 。有了这样一个空间之后,在它里面就可以去存放相应的新生代对象。新生代对象其实指的就是存活时间较短的对象,如何界定存活时间较短呢?举个例子,比如在当前代码内有一个局部作用域,这个局部作用域当中的变量在执行完成过后,就肯定要去释放回收。而我们在其他的地方,比如全局的地方也可能会有一个变量。而全局下方的这个变量它肯定要等到程序退出之后,才会被回收。所以相对来说新生代就指的是存活时间比较短的变量对象。
V8 当中如何完成新生代对象回收的?
这个过程当中所采用的算法主要就是复制算法和标记整理算法操作。首先它会将会将当前左侧的小空间也去分成两个部分:From、To,而且这两个部分的大小是相等的。From 空间成为使用状态、To为空闲状态,有了这样两个空间之后代码在执行的时候如果要申请空间要进行使用,那么首先会将的变量对象都分配至 From 空间。一旦 From 空间应用到一定程度之后,就会触发 GC 操作,这个以后就会采用标记整理的操作来对 From 空间进行活动对象的标记。找到活动对象之后会继续使用整理操作将空间位置变得连续,也便于后续不会产生空间碎片化。做完这些操作之后会将活动对象拷贝至 To 空间,拷贝完成以后就意味着之前 From 空间当中活动对象就有了一个备份。后面就是回收操作,这个回收操作就是将原 From 空间进行整体的释放回收,并将 From 空间与 To 空间进行交换。
回收细节说明
首先在这个过程当中,肯定会想到的一个现象就是如果在拷贝时发现某个变量对象所使用的空间在当前的老生代对象里面也会出现。这个时候就会出现晋升的操作,晋升指的就是将新生代的对象移动至老生代进行存储。至于说什么时候可以触发晋升操作呢?在这一般有两个判断标准:
- 如果新生代某些对象经过一轮 GC 之后它还活着,这个时候就可以把它拷贝至老生代存储区进行存储操作;
- 如果说当前拷贝的过程中,发现 To 空间使用率超过了 25% 这个时候也需要将这次的活动对象,都移动至老生代存储区中进行存放。之所以界限是 25% 是因为在将来进行回收操作时最终是要把 From 空间和 To 空间进行交换,也就是说以前的 To 会变成 From这就意味着 To 的使用率如果达到了 80% 最终它变成活动对象的一个存储空间后。那么新的对象好像就存不进去了,简单说就是 To 空间的使用率如果超过一定的限制那么将来它变成使用状态时,新进来的对象空间就不够用了。