目录
- 认识V8
- V8垃圾回收策略
- V8常用的GC算法
- V8的分代回收
- V8的内存分配
- 新生代对象回收
- 主要使用算法
- 回收过程
- 晋升
- 回收老生代对象
- 主要使用算法
- 标记增量如何优化垃圾回收?
- 新生代 VS 老生代
认识V8
-
V8
—— 是Google
发布的主流的开源JavaScript
引擎,采用C++
编写。采用即时编译,直接翻译成机器语言,并且使用了如内联缓存(inline caching
)等方法来提高性能。有了这些功能,JavaScript
程序在V8
引擎下的运行速度媲美二进制程序。 -
V8
内存设限:-
64bit
操作系统上不超过1.5G
-
32bit
操作系统上不超过800M
这么设限为了浏览器使用内存足够,内部还有垃圾运行机制,时间也在用户感知的合理范围
-
-
目前
V8
垃圾回收采用增量标记算法需要50ms
,采用非增量标记算法需要1s
V8垃圾回收策略
程序的使用过程中,可以分为 原始类型数据 和 对象类型数据 。
原始数据都是由程序语言自身控制的,这里的回收还是指主要存活在堆区的对象数据,这个过程是离不开内存操作的,V8
也是对内存做了上限,那在这种情况下是如何对垃圾进行回收的?
- 采用分代回收的思想
- 内存分为新生代存储区、老生代存储区
- 针对不同代采用不同的算法
所以V8
中会用到更多的GC
算法,这里对GC
算法不懂的还有这篇文章中说到的标记清除、整理等算法详细介绍在这篇文章中,此文章不再进行赘述
V8常用的GC算法
- 分代回收 (一定会用)
- 空间复制
- 标记清除
- 标记整理
- 标记增量 (提高效率用)
V8的分代回收
- 新生代 —— 就是指存活时间较短的对象,例如:一个局部作用域中,只要函数执行完毕之后变量就会回收。
- 老生代 —— 就是指存活时间较长的对象,例如:全局对象,闭包变量数据。
V8的内存分配
V8
内存空间一分为二,分为新生代存储区和老生代存储区,如图:
- 左边小空间用于存储新生代对象
-
64bit
操作系统上不超过32M
-
32bit
操作系统上不超过16M
-
- 右边较大空间用于存储老生代对象
-
64bit
操作系统上不超过1.6G
-
32bit
操作系统上不超过700M
-
新生代对象回收
主要使用算法
采用赋值算法 + 标记整理算法
回收过程
新生代内存区分为两个等大小空间,使用空间为From
,空闲空间为To
。
如果需要申请空间使用,回收步骤如下:
- 首先会将所有活动对象存储于
From
空间,这个过程中To
是空闲状态。 - 当
From
空间使用到一定程度之后就会触发GC
操作,这个时候会进行标记整理对活动对象进行标记并移动位置将使用空间变得连续,便于后续不会产生碎片化空间。 - 将活动对象拷贝至
To
空间,拷贝完成之后活动空间就有了备份,这个时候就可以考虑回收操作了。 - 把
From
空间完成释放,回收完成 - 对
From
和To
名称进行调换,继续重复之前的操作。
总结就是:
使用From
->触发GC标记整理
->拷贝到To
->回收From
->名称互换重复之前
晋升
拷贝的过程中某个对象的指代在老生代空间,就可能出现晋升。 晋升就是将新生代对象移动至老生代。
什么时候触发晋升操作?
- 一轮
GC
之后还存活的新生代对象需要晋升- 在拷贝过程中,
To
空间的使用率超过25%
,将这次的活动对象都移动至老生代空间
为什么是限制To的使用率呢?
将来回收操作是要把
From
空间的内容拷贝到To
空间中进行交换,如果To
的使用率太高,变成From
之后新的对象就存不进去了。
回收老生代对象
主要使用算法
主要采用标记清除 (首要) 、标记整理、增量标记算法
-
标记清除
:虽然使用标记清除会有空间碎片化的问题,但是标记清除提升的速度是很快的。 -
标记整理
:在晋升的时候且老生代区域的空间也不够容纳的时候,就会采用标记整理进行 空间优化。 -
增量标记
:将一整段的垃圾回收操作标记拆分成多个小段完成回收,主要是为了实现程序和垃圾回收的交替完成,这样进行 效率优化 带来的时间消耗更加的合理。
之前标记清除和整理的原理都在GC那篇文章中解释,这里就详情看看增量标记是如何工作的?
标记增量如何优化垃圾回收?
看图可以将垃圾回收分成两个部分,一个是程序的执行,一个是垃圾的回收。当垃圾回收的时候其实会阻塞程序的执行,所以中间会有空档期。
image新生代 VS 老生代
- 新生代区域垃圾回收使用空间换时间
- 主要采用复制算法,要有空闲空间存在,当然新生代本身空间小,分出来的复制的空间更小,所以浪费这点空间换取时间的效率是微不足道的
- 老生代区域垃圾回收不适合复制算法,老生代空间大一分为二,会造成一半的空间浪费,存放数据多复制时间长。
网友评论