编译原理实战课
宫文学
北京原点代码 CEO
26066 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 55 讲
真实编译器解析篇 (19讲)
编译原理实战课
15
15
1.0x
00:00/00:00
登录|注册

32 | 运行时(二):垃圾收集与语言的特性有关吗?

分代收集、增量收集、并发收集
标记-清除算法需要从GC根出发,找到所有存活对象
采用分代收集策略
编译器生成相应指令,处理引用计数的增减
使用两个列表保存待扫描和可能的垃圾对象
每个数据都是对象,采用引用计数算法
减少停顿时间的垃圾收集方法
区分新生代和老一代对象,采用不同回收方法
对象保存被引用数量,为零时回收
分为新旧空间,拷贝可达对象到新空间
标记可达对象后,整理内存,消除碎片
从GC根节点出发,标记可达对象,清除剩余对象
如何能减少停顿时间?
为什么在垃圾收集时,要停下整个程序?
Java、JavaScript(V8)、Julia
编译器如何配合引用计数算法
循环检测算法
Python的内存管理和垃圾收集机制
增量收集和并发收集
分代收集
引用计数
停止-拷贝
标记-整理
标记-清除
其他语言是怎么做垃圾收集的?
Python与引用计数算法
垃圾收集算法概述
运行时(二):垃圾收集与语言的特性有关吗?

该思维导图由 AI 生成,仅供参考

你好,我是宫文学。今天,我们继续一起学习垃圾收集的实现机制以及与编译器的关系。
对于一门语言来说,垃圾收集机制能够自动管理从堆中申请的内存,从而大大降低程序员的负担。在这门课的第二大模块“真实编译器解析篇”中,我们学习 Java、Python、Go、Julia 和 JavaScript 这几门语言,都有垃圾收集机制。那在今天这一讲,我们就来学习一下,这些语言的垃圾收集机制到底有什么不同,跟语言特性的设计又是什么关系,以及编译器又是如何配合垃圾收集机制的。
这样如果我们以后要设计一门语言的话,也能清楚如何选择合适的垃圾收集机制,以及如何让编译器来配合选定的垃圾收集机制。
在讨论不同语言的垃圾收集机制之前,我们还是需要先了解一下,通常我们都会用到哪些垃圾收集算法,以及它们都有什么特点。这样,我们才能深入探讨应该在什么时候采用什么算法。如果你对各种垃圾收集算法已经很熟悉了,也可以从这一讲的“Python 与引用计数算法”开始学习;如果你还想理解垃圾收集算法的更多细节,也可以去看看我的第一季课程《编译原理之美》的第 33 讲的内容。

垃圾收集算法概述

垃圾收集主要有标记 - 清除(Mark and Sweep)、标记 - 整理(Mark and Compact)、停止 - 拷贝(Stop and Copy)、引用计数、分代收集、增量收集和并发收集等不同的算法,在这里我简要地和你介绍一下。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

垃圾收集算法是自动内存管理的核心,不同的算法有不同的特点。本文介绍了标记-清除、标记-整理、停止-拷贝、引用计数、分代收集、增量收集和并发收集等算法。其中,标记-清除算法从GC根节点出发,标记可达对象,清除垃圾;标记-整理算法在清除垃圾后整理内存,避免内存碎片;停止-拷贝算法将内存分为新旧空间,拷贝可达对象到新空间。Python采用引用计数算法,通过引用数判断对象是否为垃圾。文章还介绍了Python的内存管理特征和垃圾回收算法,以及其他语言和编译器采用引用计数的情况。编译器在配合引用计数算法时,需要生成相应的指令来做引用数的增减,并可以通过逃逸分析等优化算法提高程序性能。总体而言,本文涵盖了垃圾收集算法的核心原理和不同语言的应用情况,对于想要深入了解垃圾收集机制的读者具有很高的参考价值。 文章还介绍了其他语言如Java、JavaScript(V8)和Julia等的垃圾收集策略,它们通常采用分代收集的策略,针对新生代采用标记-清除或停止拷贝算法。相比引用计数算法,这些语言避免了引用计数的缺点,如增减引用计数所导致的计算量较大,在多线程情况下需要用到锁,以及可能导致内存碎片化和局部性差等问题。此外,文章还探讨了针对服务端程序开发的Java和Go语言在垃圾收集方面的需求,以及它们致力于减少垃圾收集导致的停顿时间的努力。最新的垃圾收集器已经使得垃圾收集导致的停顿降低到了几毫秒内。同时,文章解释了在垃圾收集时为何需要停下整个程序以及如何减少停顿时间的方法。 总的来说,本文深入探讨了垃圾收集算法的原理和不同语言的应用情况,对于想要了解垃圾收集机制的读者具有很高的参考价值。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《编译原理实战课》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(3)

  • 最新
  • 精选
  • Tino's Park
    文章有几个问题请教下: 1. Go的GC目前为止(1.14.3)是非分代,非移动的并发算法(三色标记)算法,不是分代的; 2. 并发标记算法还有有一个问题,就是write-barrier在扫描期间,也需要一直运行,从而干扰业务的执行; 3. 关于STW,在大数据量下目前很难做到较优吧。

    作者回复: 关于1,多谢指出,是我疏忽了。我查了一下,Go目前确实没有实现分代的gc算法。不过,Go似乎计划在未来实现一种“基于请求的回收算法(Request Oriented Collection,ROC),其实质也是某种分代算法:新对象及时回收。 关于2,多谢补充! 关于3,STW是GC的难点。GC又是实现现代语言的难点,目前很难有什么突破性的进展。如果我来实现一门新护眼,那么会采取几个办法来客服这个问题:1.在某些编程领域,根本性地避免gc,就像rust那样;2.像erlang那样,由于对运行机制做了限制,从而降低了gc的难度;3.采用引用计数的方法,就像Objective C、swift和方舟编译器那样,会比较均匀的让整个程序变慢,但不会突然STW。 https://docs.google.com/document/d/1gCsFxXamW8RRvOe5hECz98Ftk-tcRRJcDFANj2VwCB0/edit”

    2020-09-18
    2
    2
  • D
    增加内置关键字支持不可变对象,比如像rust,Scala等语言。

    作者回复: Great!不可变确实对垃圾收集有帮助。在39讲函数式编程中也会提到这一点。

    2020-08-26
  • 写点啥呢
    请问宫老师,增量收集算法,看上去是在增量做标记,这样可以尽量不打断程序的情况下完成标记(屏障代码会带来一定性能影响),不知道我的理解对么? 进而有个疑问,如果程序的对象变化非常频繁,导致增量过程一直无法完成(就是灰色集合始终不为空)那什么时候才能做内存回收释放呢?

    作者回复: 并行收集是尽量不打断程序做收集,而增量收集是每次终端时间都尽量短。 你说的情况,确实体现了垃圾收集的复杂性,又要终端时间尽量短,又不要造成堆积,在两方面做好权衡。 对于你说的这种情况,要么增加每次暂停处理的量,要么就必须有一次较长时间的暂停,彻底做回收。

    2020-08-26
收起评论
显示
设置
留言
3
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部