We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
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
此段为 朴灵 《深入浅出 Node.js》 阅读笔记。
在 V8 中,所有 JavaScript 的对象都是通过 堆来分配 的。
当我们在代码中声明变量并赋值时,所使用对象的内存就分配在堆中。如果已申请的堆空闲内存不够分配新的对象,将继续申请堆内存,直到堆大小超过V8的限制。
那为什么 V8 要限制堆大小?
V8 的垃圾回收策略主要基于 分代式垃圾回收 机制。因为实际应用中,对象的生存周期长短不一,不同的算法只针对特定情况有最好效果,所以现代垃圾回收算法中,按对象存活时间将内存的垃圾回收进行不同的分代,然后分别运用不同算法。
V8 主要将内存分为 新生代 和 老生代 两代。新生代中的对象为存活时间较短的对象,老生代中的对象为存活时间较长或常驻内存的对象。
新生代的对象主要通过 Scavenge 算法进行垃圾回收。而 Scavenge 的具体实现中,采用 Cheney 算法—— 一种采用复制方式实现的垃圾回收算法:
Scavenge 的缺点是只能使用堆内存的一半,但由于只复制存活对象,并且由于生命周期短的场景中存活对象只占少部分,所以它在时间效率上不错。
当一个对象经过多次复制依然存活时,它会被认为是生命周期较长的对象,会被移动到老生代中,采用新的算法进行管理。对象从新生代移动到老生代称为晋升。
不同于单纯的 Scavenge 过程,在分代式垃圾回收的前提下,From 空间的存活对象复制到 To 空间前需要进行检查:即是否可以晋升。
晋升的两个条件:
对于老生代,由于存活对象占比高,采用 Scavenge 会有两个问题:
所以老生代采用 Mark-Sweep 和 Mark-Compact 相结合的方式进行垃圾回收。
Mark-Sweep,即标记清除 ,分为标记和清除两个阶段。
相比 Scavenge ,Mark-Sweep 不存在浪费空间的行为,只清理死亡对象。
当 Mark-Sweep 最大的问题是在 进行一次标记清除回收后,内存空间会存在不连续的状态 。这种内存碎片会对后续的内存分配造成问题,因为很可能出现需要分配一个大对象的情况,这时所有的碎片空间都无法完成此次分配,就会提前触发垃圾回收,而这次垃圾回收是不必要的。
Mark-Compact 可以解决内存碎片的问题,Mark-Compact 是 标记整理 ,在 Mark-Sweep 基础上演变而来。它们的差别在于在标记后,在整理的过程中,将活着的对象向一端移动,移动完成后,直接清理掉边界外的内存。
为避免出现 JavaScript 应用逻辑与垃圾回收器看到的不一致的情况,以上 3 种垃圾回收算法都需要将应用逻辑暂停,执行回收后再运行——即全停顿(stop-the-world)。
为了降低全堆垃圾回收带来的停顿时间,V8 从标记阶段入手,将全量标记改为增量标记,垃圾回收与应用逻辑交替执行,直到标记阶段完成。
The text was updated successfully, but these errors were encountered:
Java Garbage Collection Basics
可配合Java垃圾收集对照阅读。可以看到,垃圾收集原理都是一致的。
Sorry, something went wrong.
No branches or pull requests
1. 垃圾回收
在 V8 中,所有 JavaScript 的对象都是通过 堆来分配 的。
当我们在代码中声明变量并赋值时,所使用对象的内存就分配在堆中。如果已申请的堆空闲内存不够分配新的对象,将继续申请堆内存,直到堆大小超过V8的限制。
那为什么 V8 要限制堆大小?
V8 的垃圾回收机制
V8 的垃圾回收策略主要基于 分代式垃圾回收 机制。因为实际应用中,对象的生存周期长短不一,不同的算法只针对特定情况有最好效果,所以现代垃圾回收算法中,按对象存活时间将内存的垃圾回收进行不同的分代,然后分别运用不同算法。
V8 的内存分代
V8 主要将内存分为 新生代 和 老生代 两代。新生代中的对象为存活时间较短的对象,老生代中的对象为存活时间较长或常驻内存的对象。
新生代:Scavenge 算法
新生代的对象主要通过 Scavenge 算法进行垃圾回收。而 Scavenge 的具体实现中,采用 Cheney 算法—— 一种采用复制方式实现的垃圾回收算法:
Scavenge 的缺点是只能使用堆内存的一半,但由于只复制存活对象,并且由于生命周期短的场景中存活对象只占少部分,所以它在时间效率上不错。
当一个对象经过多次复制依然存活时,它会被认为是生命周期较长的对象,会被移动到老生代中,采用新的算法进行管理。对象从新生代移动到老生代称为晋升。
不同于单纯的 Scavenge 过程,在分代式垃圾回收的前提下,From 空间的存活对象复制到 To 空间前需要进行检查:即是否可以晋升。
晋升的两个条件:
老生代:Mark-Sweep & Mark-Compact
对于老生代,由于存活对象占比高,采用 Scavenge 会有两个问题:
所以老生代采用 Mark-Sweep 和 Mark-Compact 相结合的方式进行垃圾回收。
Mark-Sweep,即标记清除 ,分为标记和清除两个阶段。
相比 Scavenge ,Mark-Sweep 不存在浪费空间的行为,只清理死亡对象。
当 Mark-Sweep 最大的问题是在 进行一次标记清除回收后,内存空间会存在不连续的状态 。这种内存碎片会对后续的内存分配造成问题,因为很可能出现需要分配一个大对象的情况,这时所有的碎片空间都无法完成此次分配,就会提前触发垃圾回收,而这次垃圾回收是不必要的。
Mark-Compact 可以解决内存碎片的问题,Mark-Compact 是 标记整理 ,在 Mark-Sweep 基础上演变而来。它们的差别在于在标记后,在整理的过程中,将活着的对象向一端移动,移动完成后,直接清理掉边界外的内存。
Incremental Marking 增量标记
为避免出现 JavaScript 应用逻辑与垃圾回收器看到的不一致的情况,以上 3 种垃圾回收算法都需要将应用逻辑暂停,执行回收后再运行——即全停顿(stop-the-world)。
为了降低全堆垃圾回收带来的停顿时间,V8 从标记阶段入手,将全量标记改为增量标记,垃圾回收与应用逻辑交替执行,直到标记阶段完成。
The text was updated successfully, but these errors were encountered: