这几天花时间完成了标记-清除算法、标记-整理算法、标记-复制算法,还算顺利。今天准备动手写G1,整理思路过程中发现G1涉及到的概念相当多而且还难以理解,网上的文章、相关书籍对相关概念的解释相对比较孤立、比较简洁,需要结合很多资料串起来想才能想明白。防止后面忘记,也为了保证G1的顺利完成,码点文字把这点明白记录下来。

JVM的内存结构是由垃圾回收算法决定的。

Region

G1及其后出现的垃圾收集器ZGC、Shenandoah,它们都是基于Region的内存布局形式。它们垃圾收集的目标范围不再是整个新生代(Minor GC)、老年代(Majon GV)、整个堆(Full GC),而是一个一个的Region。因为这样的内存布局,所以G1能做到面向局部收集。

每个Region都可以被标记为E(Eden)、S(Survivor)、O(Old)、H(Humongous),但一个Region同一时刻只能是这四个中的一个。H表示巨型对象,即超过Region大小的一半的对象,会直接进入老年代由多个连续的Region存储。

Region的大小可以通过-XX:G1HeapRegionSize参数指定,如果没有显示指定,则G1会计算出一个合理的大小。Region的取值范围为1M~32M,且应为2的N次幂,所以Region的大小只能是1M、2M、4M、8M、16M、32M。比如-Xmx=16g -Xms=16g,则Region的大小等于16G / 2048=8M。也可以推理出G1推荐的管理的最大堆内存是64G。

RSet(Remembered Set、记忆集)

在垃圾收集过程中,会存在一种现象,即跨代引用,在G1中,又叫跨Region引用。如果是年轻代指向老年代的引用我们不用关心,因为即使Minor GC把年轻代的对象清理掉了,程序依然能正常运行,而且随着引用链的断掉,无法被标记到的老年代对象会被后续的Major GC回收。如果是老年代指向年轻代的引用,那这个引用在Minor GC阶段是不能被回收掉的,那如何解决这个问题呢?

最简单的实现方式当然是每个对象中记录这个跨Region引用记录,GC时扫描所有老年代的对象,显然这是一个相当大的Overhead。为什么呢?因为IBM做过这样的实验,发现绝大多数对象都是“朝生夕灭”,等不到进入老年代,能进入老年代的对象最多不到5%。JVM的新生代内存比例是8:1:1也是基于这个结论设定的。

最合理的实现方式自然是记录哪些Region中的老年代的对象有指向年轻代的引用。GC时扫描这些Region就行了。这就是RSet存在的意义。RSet本质上是一种哈希表,Key是Region的起始地址,Value是一个集合,里面存储的元素是卡表的索引号(第几个Card的第几个元素)。

Card Table(卡表)

每个Region又被分成了若干个大小为512字节的Card,这些Card都会记录在全局卡表中。Card中的每个元素对应着其标识的内存区域中一块特定大小的内存块,这个内存块被称为卡页。一个卡页的内存中通常不止一个对象,只有卡页中有一个及以上对象的字段存在着跨Region引用,这个对应的元素的值就标识为1。

比如G1默认的Region有2048个,默认每个Region为2M,那每个Region对应的Card的每个元素对应的卡页的大小为2M / 512=4K,即这4K内存中只要有一个或一个以上的对象存在着跨Region对年轻代的引用,这个卡页对应的Card的元素值为1。


这样在Minor GC时,只需要将变脏的Region中的那个卡页加入GC Roots一并扫描即可。比起扫描老年代的所有对象,大大减少了扫描的数据量,提升了效率。

思路已经理清楚,开始敲代码实现…感觉会很有意思。

结语

我是子牙老师,如果你也喜欢研究底层,喜欢硬核知识,欢迎关注我的公众号:硬核子牙

G1实现原理之记忆集与卡表相关推荐

  1. 记忆集、卡表、G1垃圾收集器简介

    记忆集 在新生代做GCRoots可达性扫描过程中可能会碰到跨代引用的现象这种如果又去对老年代再去扫描效率太低了为此 在新生代引入记录集(Remember Set)的数据结构(记录从非收集区到收集区的指 ...

  2. JVM(3)之垃圾回收(GC垃圾收集器+垃圾回收算法+安全点+记忆集与卡表+并发可达性分析......)

    <深入理解java虚拟机>+宋红康老师+阳哥大厂面试题2总结整理 一.堆的结构组成 堆位于运行时数据区中是线程共享的.一个进程对应一个jvm实例.一个jvm实例对应一个运行时数据区.一个运 ...

  3. HotSpot垃圾算法实现之记忆集与卡表和写屏障

    问题一:对象跨代(区域)引用,GC Roots扫描范围如何界定? 当部分区域进行垃圾收集时,如果非收集区域的对象跨区引用了收集区域的对象(收集区域的对象A可能被非收集区域的对象静态字段B引用,这样对象 ...

  4. 记忆集、卡表与写屏障

    提出问题 分代收集理论的时候,会存在为了解决对象跨代引用所带来的的问题.垃圾收集器在新生代中建立啦名字为挤一挤的数据结构,用来避免把整个老年代加进GC roots扫描范围.事 实上并不只是新生代.老年 ...

  5. 安全点、安全区域、记忆集、卡表与写屏障

    一.安全点(safe point) 1.1.定义 用户程序执行时并非在代码指令流的任意位置都能够停顿下来开始垃圾收集,而是强制要求必须执行到达特殊位置后才能够暂停,这些位置被称为安全点 ( Safep ...

  6. jvm根节点枚举、安全点、安全区域、记忆集、卡表、写屏障、并发的可达性分析

    讲具体的实现之前,先说说几个和这些垃圾回收器息息相关的一些知识点,可以有一个更好的理解 1.根节点枚举 也就是可达性分析算法从GC Roots集合中找引用链的过程,可作为GC Roots的节点主要在全 ...

  7. 跨代引用、记忆集、卡表

    一.什么是跨代引用? 新生代中的对象持有了老年代中的对象的引用 或 老年代中的对象持有了新生代中对象的引用. 如下图所示,新生代中的A对象持有了老年代中C对象的引用:老年代中的C对象持有了新生代中B对 ...

  8. Hotspot细节实现安全区域、记忆集卡表

    Hotspot细节实现 文章目录 Hotspot细节实现 3.安全区域 产生原因 安全区域概念 实现过程 4.记忆集与卡表 产生原因: 记忆集概念 实现过程: 卡精度(卡表) 3.安全区域 产生原因 ...

  9. 面试篇之JVM(GC 可达性分析 回收算法 卡表 G1)

    面试篇之JVM 面试篇之JVM GC 对象存活判断 分代回收理论 常见回收算法 HotSpot实现细节 记忆集与卡表 读写屏障 回收器 并发标记 G1 面试篇之JVM GC 美团 1.JVM怎么判断一 ...

最新文章

  1. 【安装PHP】如何在openSUSE42.1下编译安装PHP7
  2. javase学习第10天(形式参数和返回值类型、包、内部类、匿名内部类)
  3. CodeForces - 1419E Decryption(质因子分解+构造)
  4. 《算法导论》读书笔记之第1章 算法在计算机中的作用
  5. SpringBoot项目集成Mybatis Plus(二)代码生成器
  6. 家长工作比较忙,没有什么时间来带孩子,交给家里老人会养成一些坏习惯吗?
  7. 人员基础信息一体化采集仪_注意!会计人员信息采集,哪些人需要采集?
  8. Linux命令:tac
  9. mac乱码 飞秋_ubuntu 下安装 dukto
  10. GridView样式
  11. 详解CAN 2.0协议
  12. 优秀网页翻译:Raspberry Pi + OpenCV 进行 360° 街景拼接
  13. ​LeetCode刷题实战196:删除重复的电子邮箱
  14. Apktool命令使用总结
  15. php 表格序号,excel自动生成序号、编号
  16. AB post 请求压测
  17. STM32H7链接器脚本文件分析
  18. 普通程序员真实的各个面试心酸历程——愿世界没有Java技术面试
  19. 在vue中使用three.js
  20. Java调用金蝶接口

热门文章

  1. 哪种需求适合选择动态拨号VPS
  2. Mac安装VM虚拟机
  3. 基于稀疏点云地图实现Turtlebot2真实环境下导航
  4. 啊哈,算法 !--火柴棍公式 ( C语言版 )
  5. 上海交大跨专业考研计算机,跨专业考取上海交大计算机研究生其实并不难_跨考网...
  6. 在非洲运营互联网系统-系统研发历程(上)
  7. Scrapy爬虫之爬取当当网图书畅销榜
  8. 物美与价廉,名创优品能否兼得?
  9. 什么是机器人的五点校正法_机器人校准
  10. 社交媒体该如何实现「去中心化」?