Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

垃圾回收机制 #17

Open
Genluo opened this issue Aug 31, 2019 · 0 comments
Open

垃圾回收机制 #17

Genluo opened this issue Aug 31, 2019 · 0 comments

Comments

@Genluo
Copy link
Owner

Genluo commented Aug 31, 2019

准确的来说应该是V8引擎的垃圾回收机制。

V8为什么要限制堆大小

因为V8做一次小的垃圾回收需要50ms以上,做一次非增量式垃圾回收甚至需要1秒以上,这是垃圾回收引起js线程暂停的执行时间,在这样的时间花销上,应用的性能和响应能力都会直线下降,这种情况不仅仅后端服务器无法接受,同时客户端也无法接受,因此,在当时的情况下直接限制堆内存是一个好的方法。

V8垃圾回收算法

采用的策略主要是基于分代式垃圾回收机制,按照对象的存活时间将内存中的垃圾回收进行不同的分代,然后对不同的代使用不同的高效算法,V8中主要将内存分为新生代的内存空间,老生代的内存空间,新生代的内存空间主要使用Scavenga算法,老生代内存空间主要使用Mark-Sweep和Mark-Compact相结合的方式进行垃圾回收

  • Scavenga算法

这是一种采用复制的算法,它将堆内存一分为2,每一部分空间称之为semispace,这两个空间中只有一个空间使用,另一个处于闲置状态,我们将处于使用状态的空间称之为From空间,处于闲置的空间称之为To空间,当我们进行垃圾回收的时,首先会检查From空间中的存活对象,这些存活对象将被复制到To空间,而非存活对象的空间将会别释放,完成复制以后,From空间To空间角色将会发生对换。这种算法称之为Cheney算法,但是在V8中,因为我们将内存分为新生代内存和老生代内存,所以我们要对算法进行一些调整,这个过程称之为晋升,晋升主要有两个条件,一个是当前内存对象是否经过Scavenga回收,另一个是当前To的空间已经使用了25%,当符合其中任意一个条件的时候,我们直接将此活动对象移动到老生代内存中。这个算法的优点就是速度,缺点就是浪费空间。

第一种情况

第二种情况

  • Mark-Sweep和Mark-Compact

在老生代的对象中,不采用上面那种算法,主要是有两个原因,一个就是存活对象很多,复制存活对象效率很低,另一个原因就是浪费一半内存空间的原因。

首先谈下Mark-Sweep算法,这个是标记-清除的意思,它分为标记和清除两个阶段,标记阶段遍历堆中所有的对象,并且标记活着的对象,在随后的清除阶段中,只清除没有标记的对象,可以看出Scavenge算法只复制活着对象,Mark-Sweep算法只清除死亡的对象,因为在新生代对象中,活对象只占新生对象的少部分,同理,死对象也只是占老生对象的少部分,这就是两种算法的高效地方,但是现在还存在一个事情,就是使用Mark-Sweep会产生内存碎片,如何整理内存空间,清除这些内存碎片?

为了解决Mark-Sweep清除之后产生的内存碎片,提出Mark-Compact算法,这个是标记整理的意思,它和上Mark-Sweep的不同是,它不是直接清理死亡对象,而是在于对象被标记死亡之后,在整理过程中,将活着的对象往一端移动,移动完成后,直接清理边界的内存,这样就不会存在内存碎片。

这里介绍的两种算法,Mark-Compact可以替代Mark-Sweep,但是根据执行过程我们可以知道Mark-Compact会比价耗费时间,所以在V8中是将两种垃圾回收算法结合起来使用的,V8主要使用的是Mark-Sweep,在空间不足已对从新生代中晋升过来的对象进行分配的时才使用Mark-Compact算法

全停顿时间的优化

全停顿时间指的是垃圾回收和js应用逻辑看到不一致的情况,垃圾回收的三种基本算法都会讲应用逻辑停下来,待执行完垃圾回收后再恢复执行应用逻辑。

这里主要是针对老生代的空间的全堆垃圾回收(full垃圾回收),V8是这样优化的将原本要一次完成的动作改成增量标记,也就是拆分成许多小的步骤,每做完一步,就让js应用逻辑执行一小会,垃圾回收与应用逻辑交替执行直到标记阶段完成(这种主要是针对标记阶段),V8后续还引入延迟清理,增量式整理,同时还计划引入并行标记、并行清理,进一步利用多核性能降低每次停顿的时间。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant