学习内存 缓存和垃圾回收相关知识

发布于 2022-07-17 18:49:48 字数 2229 浏览 226 评论 1

在 V8 中,所有 JavaScript 的对象都是通过 堆来分配 的。

当我们在代码中声明变量并赋值时,所使用对象的内存就分配在堆中。如果已申请的堆空闲内存不够分配新的对象,将继续申请堆内存,直到堆大小超过V8的限制。

那为什么 V8 要限制堆大小?

  • 表层原因:V8 最初为浏览器而设计,无大内存场景。
  • 深层原因:V8 垃圾回收机制限制。以 1.5GB 的垃圾回收为例,V8 做一次小的垃圾回收需要 50 毫秒以上,而一次非增量式垃圾回收需要 1 秒以上。垃圾回收引起 JS 线程暂停执行,这么长时间是不可接受的。

V8 的垃圾回收机制

V8 的垃圾回收策略主要基于 分代式垃圾回收 机制。因为实际应用中,对象的生存周期长短不一,不同的算法只针对特定情况有最好效果,所以现代垃圾回收算法中,按对象存活时间将内存的垃圾回收进行不同的分代,然后分别运用不同算法。

V8 的内存分代

V8 主要将内存分为 新生代老生代 两代。新生代中的对象为存活时间较短的对象,老生代中的对象为存活时间较长或常驻内存的对象。

新生代:Scavenge 算法

新生代的对象主要通过 Scavenge 算法进行垃圾回收。而 Scavenge 的具体实现中,采用 Cheney 算法—— 一种采用复制方式实现的垃圾回收算法:

  1. 将堆内存一分为二,每个部分空间称为 semispace;
  2. 两个 semispace 一个处于使用中(称为 From 空间),一个处于空闲状态(称为 To 空间);
  3. 当我们分配对象时,在 From 空间进行分配;
  4. 当开始进行垃圾回收时,会检查 From 空间的存活对象,把它们复制到 To 空间,而非存活对象占用的空间被释放;
  5. 完成复制后,From 空间和 To 空间角色对换。

Scavenge 的缺点是只能使用堆内存的一半,但由于只复制存活对象,并且由于生命周期短的场景中存活对象只占少部分,所以它在时间效率上不错。

当一个对象经过多次复制依然存活时,它会被认为是生命周期较长的对象,会被移动到老生代中,采用新的算法进行管理。对象从新生代移动到老生代称为晋升。

不同于单纯的 Scavenge 过程,在分代式垃圾回收的前提下,From 空间的存活对象复制到 To 空间前需要进行检查:即是否可以晋升。

晋升的两个条件:

  • 对象是否经历过(一次) Scavenge 回收;
  • To 空间的内存占用超过一定比例,比如 25%。设置比例是因为此次 Scavenge 回收完成后, To 空间将变成 From 空间,占用比例过高将影响后续内存的分配。

老生代: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 从标记阶段入手,将全量标记改为增量标记,垃圾回收与应用逻辑交替执行,直到标记阶段完成。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

后eg是否自 2022-04-30 05:22:41

Java Garbage Collection Basics

可配合Java垃圾收集对照阅读。可以看到,垃圾收集原理都是一致的。

~没有更多了~

关于作者

去了角落

暂无简介

0 文章
0 评论
22 人气
更多

推荐作者

烙印

文章 0 评论 0

singlesman

文章 0 评论 0

独孤求败

文章 0 评论 0

晨钟暮鼓

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文