深入拆解 Java 虚拟机
郑雨迪
Oracle 高级研究员,计算机博士
87446 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 40 讲
模块四:黑科技 (3讲)
深入拆解 Java 虚拟机
15
15
1.0x
00:00/00:00
登录|注册

11 | 垃圾回收(上)

执行即时编译器生成的机器码
解释执行字节码
JNI本地代码
安全点检测
稳定的执行状态
安全词
已启动且未停止的Java线程
JNI handles
已加载类的静态变量
Java方法栈桢中的局部变量
堆使用效率低下
解决内存碎片化问题
性能开销
解决内存碎片化问题
缺点:内存碎片、分配效率低
方法入口
方法出口
安全点的目的
安全点机制
解决循环引用问题
GC Roots
漏洞:无法处理循环引用对象
复制(copy)
压缩(compact)
清除(sweep)
安全点检测的开销
安全点检测的位置
Stop-the-world
可达性分析
引用计数法
垃圾回收的三种方式
Stop-the-world以及安全点
引用计数法与可达性分析
JVM中的垃圾回收(上)
垃圾回收

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

你应该听说过这么一句话:免费的其实是最贵的。
Java 虚拟机的自动内存管理,将原本需要由开发人员手动回收的内存,交给垃圾回收器来自动回收。不过既然是自动机制,肯定没法做到像手动回收那般精准高效[1] ,而且还会带来不少与垃圾回收实现相关的问题。
接下来的两篇,我们会深入探索 Java 虚拟机中的垃圾回收器。今天这一篇,我们来回顾一下垃圾回收的基础知识。

引用计数法与可达性分析

垃圾回收,顾名思义,便是将已经分配出去的,但却不再使用的内存回收回来,以便能够再次分配。在 Java 虚拟机的语境下,垃圾指的是死亡的对象所占据的堆空间。这里便涉及了一个关键的问题:如何辨别一个对象是存是亡?
我们先来讲一种古老的辨别方法:引用计数法(reference counting)。它的做法是为每个对象添加一个引用计数器,用来统计指向该对象的引用个数。一旦某个对象的引用计数器为 0,则说明该对象已经死亡,便可以被回收了。
它的具体实现是这样子的:如果有一个引用,被赋值为某一对象,那么将该对象的引用计数器 +1。如果一个指向某一对象的引用,被赋值为其他值,那么将该对象的引用计数器 -1。也就是说,我们需要截获所有的引用更新操作,并且相应地增减目标对象的引用计数器。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

本文介绍了Java虚拟机中的垃圾回收机制及其基础知识。首先介绍了引用计数法和可达性分析两种垃圾回收算法,指出可达性分析算法能有效解决循环引用问题。文章详细解释了Stop-the-world机制和安全点的概念,以及在多线程环境下的应用。此外,还介绍了垃圾回收的三种方式:清除、压缩和复制,并指出现代垃圾回收器往往会综合这些方式。总的来说,本文通过深入浅出的方式,解释了垃圾回收的基础知识和相关机制,对读者快速了解Java虚拟机中的垃圾回收提供了全面的概览。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《深入拆解 Java 虚拟机》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(74)

  • 最新
  • 精选
  • 旭东(Frank)
    置顶
    赞,这种循序渐进的讲法,不知道了怎么工作,还知道了为啥要设计成这样,Why和what都和谐的在一起讲了
    2018-08-28
    18
  • 置顶
    非常感谢,此篇可用通俗易懂来形容,其他同学问的问题也很棒! 小结: 1:垃圾回收-核心工作就是回收垃圾,哪关键点回来了。什么是垃圾?这个垃圾需要分类嘛?怎么定位垃圾?怎么回收垃圾?回收垃圾的方法都有哪些?他们都有什么优缺点?另外,就是我们为什么要学习垃圾回收? 2:站在JVM的视角来看 垃圾-就是无用对象所占用的堆内存空间 貌似不需要垃圾分类,识别垃圾并回收就行 定位垃圾,是垃圾回收的关键点 晚安💤,明天继续写
    2018-08-16
    32
  • 非常感谢,此篇可用通俗易懂来形容,其他同学问的问题也很棒! 小结: 1:垃圾回收-核心工作就是回收垃圾,哪关键点回来了。什么是垃圾?这个垃圾需要分类嘛?怎么定位垃圾?怎么回收垃圾?回收垃圾的方法都有哪些?他们都有什么优缺点?另外,就是我们为什么要学习垃圾回收? 2:站在JVM的视角来看 垃圾-就是无用对象所占用的堆内存空间 垃圾分类-貌似不需要垃圾分类,识别垃圾并回收就行 定位垃圾-是垃圾回收的关键点,无用的对象占用的堆空间即是垃圾,那就需要先定位无用的对象,这里的无用是不再使用的意思,咋判断呢?文中介绍了两种方法,计数法和标记法(祥看原文)核心在于能定位出无用的对象,后出现的方法往往比早出现的更好一点,这里也一样,标记法能解决计数法,解决不了的循环引用不能回收的问题,但是也存在其他的问题,误报和漏报的问题,误报浪费点垃圾回收的机会浪费点空间,漏报在多线程并发工作时可能会死JVM的,所以,比较严重,所以,JVM采用了简单粗暴的stop-the-world的方式来对待,所以,老年代的回收有卡顿的现象 怎么回收垃圾-定位出垃圾,回收就是一个简单的事情了,当然也非常关键,把要回收的堆内存空间标记为可继续使用就行,下次有新对象能在此空间创建就行 回收垃圾的方法-文中介绍了三种,清除、压缩、复制 清除法-简单,但易产生碎片,可能总空间够但分配不了的问题 压缩法-能解决清除法的问题,但是复杂且耗性能 复制法-折衷一些,但是空间利用率低,总之,各有千秋 为什么要学-这个最容易,因为面试需要、装逼需要、升职加薪需要、人类天生好奇、还有免于被鄙视及可以鄙视其他人

    作者回复: 赞!

    2018-08-17
    6
    43
  • 疑问❓ 1:JVM的stop-the-world机制非常不友好,有哪些解决之道?原理是什么? 2:压测时出现频繁的gc容易理解,但是有时出现毛刺是因为什么呢? 3:fullgc有卡顿,对性能很不利,怎么避免呢?

    作者回复: 1. 采用并行GC可以减少需要STW的时间。它们会在即时编译器生成的代码中加入写屏障或者读屏障。 2. Y轴应该是时间,那毛刺就是长暂停。一般Full GC就会造成长暂停。 3. 通过调整新生代大小,使对象在其生命周期内都待在新生代中。这样一来,Minor GC时就可以收集完这些短命对象了。

    2018-08-17
    3
    29
  • Leon Wong
    老师你好,例子里的foo方法中的for循环,其中i变量类型我从int型改成long型后,长暂停的现象不存在了,请问是为何?

    作者回复: 这是C2一个诡异的地方。 for (int i=start; i<limit; i++) {..} 对于int类型的循环变量i,如果满足 1) 基于该循环变量的循环出口只有一个,即i < limit,2) 循环变量随着迭代的增量为常数,例子中i++即增量为1,以及循环变量的上限(当增量为负数时则是下限)为循环无关的,即limit应是循环无关,那么C2会将其判断成计数循环(counted loop),然后默认不插入safepoint。 而对于long类型的循环变量,C2直接识别为非计数循环,需要插入safepoint。

    2018-09-11
    3
    17
  • 浪迹江湖
    突发奇想:如果 GC 将引用计数算法和可达性分析算法结合起来使用会怎样? 循环引用毕竟是少数,如果先用引用计数算法回收掉大部分对象,再对剩余的小部分对象采用可达性分析算法解决循环引用问题。可能比只使用可达性分析算法带来更好的回收效率。

    作者回复: 赞想法!不过我认为没有达到更好的回收效率,因为垃圾回收标记的是非垃圾,剩余没有标记的对象是垃圾。用引用计数法清理后,可达性分析仍需遍历所有活着的对象。 但是可以将引用计数做成minor minor GC,只有当引用计数回收不了垃圾时,再触发可达性分析。感兴趣的话可以深入探索一下业界其他非Java runtime的垃圾回收算法。

    2018-09-26
    12
  • 正是那朵玫瑰
    老师有几个不明白的地方,误报和漏报不太明白: 1、假设A引用开始指向A1对象:A------>A1,按老师说的误报就是将引用A指向null:A------>null,那么此时A1对象不是没有引用了,不就可以垃圾回收了么,为什么会错过垃圾回收的机会呢? 2、漏报,是将A引用指向一个未被访问的对象假设对象为B:A----->B,此时A引用原来指向的对象应该没有引用了吧,为什么会垃圾回收器可能会回收事实上仍被引用的对象呢?

    作者回复: 这里指的是,GC已经标记完成,然后其他线程进行修改的情况(也是并发GC所要解决的问题)。 当GC标记完成,还未开始回收时,你更新了其中一个引用,使之指向null,那么原来指向的对象本可以被回收的。 如果指向一个新的对象,这个对象可没有被标记为不能回收,垃圾回收器就直接给回收掉了

    2018-08-15
    8
  • WolvesLeader
    很是不明白,我的理解有没有stop the word 是和垃圾回收器有关的,看完之后怎么觉得您的意思是,不管什么垃圾回收器都会出现stop the word

    作者回复: 目前的垃圾回收器多多少少需要stop the world,但都在朝着尽量减少STW时间发展。 完全的并发GC算法是存在的,但是在实现上一般都会在枚举GC roots时进行STW。

    2018-08-17
    7
  • life is short, enjoy mor...
    老师,我心中有一个疑惑。 压缩算法是不是也用到了复制呢?因为我觉得在压缩的过程中,也需要把存活的内存进行转移,而转移也就是复制吧? 麻烦老师给回答一下~

    作者回复: 确实是需要复制数据,这样起名主要是为了区分复制到同一个区域中(需要复杂的算法保证引用能够正确更新),还是复制到另一个区域中(可以复制完后统一更新引用)。

    2018-10-16
    4
  • Jerry银银
    老师,以下这段话是不是有误? 误报和漏报反了! 漏报应该是没有什么伤害,会让GC损失部分垃圾回收的机会。误报才比较麻烦,可能回收仍被引用的对象!! “误报并没有什么伤害,Java 虚拟机至多损失了部分垃圾回收的机会。漏报则比较麻烦,因为垃圾回收器可能回收事实上仍被引用的对象内存。一旦从原引用访问已经被回收了的对象,则很有可能会直接导致 Java 虚拟机崩溃。”

    作者回复: 误报是指可达性分析误认为某个对象是可达的,实际不可达。漏报是指可达性分析没有发现某个对象可达。 这里需要明确,可达性分析会找出非垃圾,而其他对象通通被认为是垃圾。

    2020-01-04
    4
    2
收起评论
显示
设置
留言
74
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部