G1垃圾收集器堆内存划分,垃圾收集各个阶段解析

G1(Garbage First Collector )

G1收集器官方文档

热点架构

HotSpot JVM具有一种体系结构,该体系结构支持强大的特性和功能基础,并支持实现高性能和大规模可伸缩性的能力。例如,HotSpot JVM JIT编译器会生成动态优化。换句话说,它们在Java应用程序运行时做出优化决策,并生成针对底层系统体系结构的高性能本机指令。此外,通过其运行时环境和多线程垃圾收集器的日趋完善和不断的工程设计,即使在最大的可用计算机系统上,HotSpot JVM仍可实现高可伸缩性。
在这里插入图片描述
JVM的主要组件包括类加载器,运行时数据区域和执行引擎

关键热点组件

下图突出显示了JVM中与性能有关的关键组件。
在这里插入图片描述
JVM的三个组件主要在调整性能时着重。该堆是你的对象数据的存储位置。然后,该区域由启动时选择的垃圾收集器管理。大多数优化选项都与调整堆大小和为您的情况选择最合适的垃圾收集器有关。JIT编译器对性能也有很大影响,但很少需要使用JVM的较新版本进行调整

评价系统指标重要的的两个因素

通常,在调整Java应用程序时,重点放在两个主要目标之一:响应性或吞吐量

响应能力

响应能力是指应用程序或系统对请求的数据做出响应的速度。示例包括:

  • 桌面用户界面对事件的响应速
  • 网站返回页面的速度
  • 数据库查询返回的速度

吞吐量

吞吐量专注于最大程度地提高应用程序在特定时间段内的工作量。如何测量吞吐量的示例包括:

  • 在给定时间内完成的交易次数。
  • 批处理程序在一小时内可以完成的作业数。
  • 一小时内可以完成的数据库查询数。

较高的用户停顿时间对于注重吞吐量的应用程序是可以接受的。由于高吞吐量应用程序会在更长的时间内专注于基准测试,因此无需考虑一时响应时间

G1垃圾收集器

垃圾优先(G1)收集器是一种服务器样式的垃圾收集器,目标是具有大内存的多处理器计算机。它极有可能满足垃圾回收(GC)暂停时间目标,同时实现高吞吐量。Oracle JDK 7更新4和更高版本完全支持G1垃圾收集器。G1收集器设计用于以下应用程序:

  1. 可以与CMS收集器之类的应用程序线程并行运行。
  2. 紧凑的自由空间,无需较长的GC引起的暂停时间
  3. 需要更多可预测的GC暂停时间。
  4. 不想牺牲很多吞吐量性能。
  5. 不需要更大的Java堆。

传统收集器只能在吞吐量(parallel scanvenge 收集器) 和 用户线程卡顿(CMS 收集器)取其一。而G1收集器取其中,在短时间满足最小化卡顿的同时满足高吞吐量

G1的优点

Oracle计划将G1作为并发标记扫描收集器(CMS)的长期替代产品。将G1与CMS进行比较,有一些差异使G1成为更好的解决方案。一个区别是G1是压紧收集器。G1足够紧凑,可以完全避免使用细粒度的空闲列表进行分配,而是依赖于区域。这大大简化了收集器的各个部分,并消除了潜在的碎片问题。此外,G1提供的垃圾收集暂停比CMS收集器更具可预测性,并允许用户指定所需的暂停目标

在这里插入图片描述
在这里插入图片描述

G1相对CMS的优势

在这里插入图片描述

传统垃圾收集器内存布局

非G1的垃圾收集器
在这里插入图片描述
所有内存对象最终都属于这三个部分之一。

G1垃圾收集器内存布局

在这里插入图片描述

  • 就是说 Eden,survivor,old 也存在 但是总的内存大小不固定,每个角色占据多少个region是不固定的
  • 也就是说上图中每个颜色都是一个regions,region之间不一定连续,每个region的可能的角色有三种 eden survivor old
  • 当执行垃圾收集时,G1以类似于CMS收集器的方式运行。G1执行并发全局标记阶段,以确定整个堆中对象的活动性。标记阶段完成后,G1知道哪些区域大部分为空(存在大量垃圾对象)。它首先收集在这些区域中,通常会产生大量的自由空间。这就是为什么这种垃圾收集方法称为“垃圾优先”的原因。顾名思义,G1将其收集和压缩活动集中在可能充满可回收对象(即垃圾)的堆区域。G1使用暂停预测模型满足用户定义的暂停时间目标,并根据指定的暂停时间目标选择要收集的区域数
  • 由G1标识为可回收的成熟区域是使用疏散收集的垃圾。G1将对象从堆的一个或多个区域复制到堆上的单个区域(如多个eden存活对象小于一个survivor内存大小
    就将其复制到survivor当中),并且在此过程中,压缩和释放了内存(在这过程被复制的region区域就会被释放掉)。复制是在多处理器上并行执行的,以减少暂停时间并增加吞吐量。因此,对于每个垃圾收集,G1都在用户定义的暂停时间内连续工作以减少碎片。这超出了前面两种方法的能力。CMS(并发标记扫描)垃圾收集器不执行压缩。ParallelOld垃圾回收仅执行整个堆压缩,这导致相当长的暂停时间。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

G1的RSet和CSet

如果从ParallelOldGC或CMS收集器迁移到G1,则可能会看到较大的JVM进程大小。这在很大程度上与“记账”数据结构有关,例如“已记忆集合(RSet)”和“收集集合(CSet)”。

  1. Remembered Sets or RSets 将对象引用跟踪到给定区域中。堆中每个区域都有一个RSet。RSet支持并行和独立地收集区域。RSets的总体影响小于5%。
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    上述的意思就是RSet其实就是哈希(hashTable)表,key记录是哪些region指向他 value记录的s是指向它的region的points-out.。 例如:regionA 的RSet 记录了regionB 此时这个RSet 的key 的值为RegionB;Value则是RegionB中指向其他区域的数据 。value是一个集合 可能他的索引只有一个是指向A,其他索引指向的是CD… 但是只要value中有一个索引指向了A 就会被RegionA的RSet记录,只不过key代表被谁指向,而value则是这个谁他所指向的区域 不一定所有索引都指向regionA但至少有一个指向A,即RSet相当于A来说B为A的points-into 为key,value相当于B来说就是B的points-out 其中至少存在一个内存对象指向A

该Rset 是Eden中记录哪些Old指向它,young GC时就只扫描指向他的GC即可

  1. Collection Sets or CSets 在GC中收集的区域集。GC期间,将(复制/移动)CSet中的所有存活数据,区域集可能是Eden,survivor,old。CSets对JVM的大小影响不到1%。

在这里插入图片描述

G1的推荐用例

G1的首要重点是为运行需要大堆且GC延迟有限的应用程序的用户提供解决方案。这意味着堆大小约为6GB或更大,并且稳定且可预测的暂停时间低于0.5秒

如果当前具有CMS或ParallelOldGC垃圾收集器的应用程序具有以下一个或多个特征,则将其切换到G1将非常有益。

  1. 完整的GC持续时间太长或太频繁。
  2. 对象分配率或晋升率差异很大
  3. 不必要的长时间垃圾收集或压缩暂停(停顿长于0.5到1秒)
    注意:如果您使用的是CMS或ParallelOldGC,并且您的应用程序未经历长时间的垃圾收集暂停,则可以保留当前的收集器。使用最新的JDK不需要更改为G1收集器。
    在这里插入图片描述

G1堆结构

G1收集器采用了另一种分配堆的方法。后续图片逐步检查了G1系统。

G1堆结构

堆是一个内存区域,分为多个固定大小的区域。
在这里插入图片描述
区域大小由JVM在启动时选择。JVM通常针对大约2000个区域,大小从1到32Mb不等。

堆分区

实际上,这些区域被映射为Eden,survivor和old空间的逻辑表现形式
在这里插入图片描述
图片中的颜色显示了哪个region与哪个角色相关联。将活动对象从一个区域撤离(即复制或移动)到另一个区域。区域被设计为:在不停止所有其他应用程序线程的情况下并发收集就是说区域垃圾在收集时和用户线程是并发的

如图所示,可以将区域分配到Eden,幸存者和旧时代区域。此外,还有第四种类型的物体被称为巨大区域(Humongous )。这些区域旨在容纳标准区域大小的50%或更大的对象。它们存储为一组连续区域(G1会有特殊的处理办法)。最后**,最后一种区域类型是堆的未使用区域**。

注意:在撰写本文时(Orecle),尚未优化收集大型对象的过程。因此,应避免创建这种大小的对象

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

G1的年轻代

堆分为大约2000个区域。最小大小为1Mb,最大大小为32Mb。蓝色区域保存旧对象,绿色区域保存年轻对象。
在这里插入图片描述
请注意,区域不需要像旧的垃圾收集器那样连续

G1中的年轻GC

当堆内存不足以为对象分配内存,将存活的对象撤离(即复制或移动)到一个或多个幸存者区域。如果满足老化阈值,则某些对象将被提升到老年代意思就是说新生代的GC存活的对象如果不够一个survivor存储可以存储多个survivor,其中超过年龄阈值的对象另外存放在老年代区域

在这里插入图片描述
这里**用户线程(会STW)停顿。需要考虑诸如用户定义的停顿时间目标**之类的事情。为下一个年轻GC计算Eden大小和survivor大小。保留会计信息以帮助计算大小。

这种方法使调整区域大小变得非常容易,可以根据需要增大或缩小区域。

带有G1的年轻GC结束

存活对象已被疏散到幸存者区域或老年代区域。在这里插入图片描述
最近晋升的对象以深蓝色显示。幸存者区域为绿色。

综上所述,关于G1的年轻一代,可以说以下几点:

  • 堆是单个内存空间,分为多个区域。
    -年轻代内存由一组非连续区域组成。这使得在需要时易于调整大小(可直接在未使用内存拿到想要的内存)。
  • 年轻代的垃圾收集器在初始标记时会STW。将停止所有应用程序线程以进行操作。
  • 年轻的GC(垃圾回收时 区别初始标记)使用多个线程并发完成。
  • 将活动对象复制到新的幸存者或老年代的region。

G1垃圾收集器阶段

G1收集器采用了另一种分配堆的方法。后续图片逐步检查了G1系统。

1.初始标记(Initial Marking Phase)

与cms类似用来标记被roots和新生代引用的老年代对象

在这里插入图片描述

2.并发标记(concurrent Marking Phase)

如果找到空白region(如“ X”所示)则在“remark”阶段将其立即删除。另外,计算确定活跃度的“accounting”的信息

在这里插入图片描述

3.重新标记(Remark Phase)

空区域将被删除并回收。现在重新计算所有区域的区域活跃度
在这里插入图片描述

4.复制/清理阶段(Copying/Cleanup Phase)

G1选择“活度”最低的区域(就是引用少垃圾多),这些区域可以被最快地收集。然后与年轻的GC同时收集这些区域。这在日志中表示为[GC pause (mixed)]。因此,年轻代和老年代都被同时收集。
在这里插入图片描述

5.复制/清理阶段之后(After Copying/Cleanup Phase)

选定的区域已被收集并压缩为图中所示的深蓝色区域和深绿色区域。改蓝色和深绿色代表的是对应区域的存活对象是被压缩分配到该区域所占的内存
在这里插入图片描述
总之,关于旧一代的G1垃圾收集,我们可以提出一些关键点。

  • 并发标记阶段
    活动信息是在应用程序运行时同时计算的。
    该活动信息标识在疏散暂停期间最适合回收的区域。
    没有像CMS中那样的清扫阶段。

  • 重新标记阶段
    使用开始快照(SATB)算法,该算法比CMS使用的算法快得多。
    完全回收空区域。

  • 复制/清理阶段
    同时回收年轻一代和老一代。
    老年人地区是根据其活跃度来选择的。

猜你喜欢

转载自blog.csdn.net/qq_42261668/article/details/109272620