当前位置:   article > 正文

JVM | GC垃圾收集器_g1两个region不是连续的

g1两个region不是连续的

1. GC简介

为什么会有GC垃圾回收器?本质上是内存资源的有限性 ,在Java开发中程序员不需要考虑垃圾回收的问题,垃圾会无限的生成,所以在有限的服务内存中没有人回收垃圾会导致空间不足OOM,所以就需要GC垃圾回收器帮我们清除垃圾。
GC是java语言的核心技术之一,在Java中程序员不需要去关心内存的动态分配和垃圾回收的问题; 如果对象没有被其他对象所引用该对象就会被视为垃圾,其占用内存就会被销毁。

2. 垃圾回收算法

2.1 标记垃圾的算法

清除垃圾的前提是需要知道什么是垃圾所以就需要标记垃圾的算法
引用计数算法: 引用计数法就是给对象添加一个引用计数器。每当一个地方引用这个对象的时候计数器就会加1,当引用失效就会减1,任何时候计数器为0的对象就是不可能在被使用的对象 就会被当作垃圾收集
优点:执行效率快 程序执行受影响较小
缺点:无法检测出循环引用的对象 会存在导致内存溢出的情况
根可达性算法:可达性分析算法是将被称为GC Roots的对象作为起点,从这些节点开始往下搜索,当一个对象到GC Roots 没有任何引用链时(既从GC Roots节点到该节点不可达),则证明该对象时不可用的。

2.2 GC的算法

标记清除算法(Mark and Sweep):
标记清除算法分为 标记和清除两个阶段: 首先标记处需要回收的对象,标记完成后统一清除对象。
优点: 效率高
缺陷: 容易产生内存碎片
标记清除
标记整理:
标记整理 与标记清除算法 标记操作是一致的,标记后清理无用对象完成后让所有存活的对象都向一端移动,并更新引用其对象的指针。
优点: 不会产生内存碎片
缺点: 因为要移动存活对象,所以效率会比“标记清除”效率低。
在这里插入图片描述
复制算法:
标记复制是将内存容量分为大小相等的两块,每次只使用启动一块。当这块用完之后就将存活的对象复制到另一块上,然后在吧一使用过的内存空间一次清理掉。
优点: 实现简单,效率高,不会存在内存碎片
缺点: 需要2倍的内存来管理。
在这里插入图片描述

3. STW、Minor GC、Major GC、FullGC

STW: Java中Stop-The-Word机制简称STW,是在执行垃圾收集算法时,Java应用程序的其他素有线程都被挂起(除了垃圾收集器的线程)。Java中一种全局暂停的现象,在执行GC的卡顿.

Minor GC: 年轻代的GC

Manjor GC: 老年代的GC

Full GC: 清理整个堆空间-包括年轻代和永久代。
各个GC垃圾收集器的 FullGC

  • 当使用G1,CMS 时,FullGC发生的时候 是 Serial+SerialOld。
  • 当使用ParalOld时,FullGC发生的时候是 ParallNew +ParallOld.

4. GC垃圾收集器

JVM 中有串行GC、并行GC、并发GC
查看当前使用的GC:jmap -heap 进程ip

4.1 Serial (串行GC)

串行GC对年轻代使用 mark-copy(标记-复制)算法,对老年代使用 mark-sweep-compact(标记-清除-整理)算法;是单线程的垃圾收集器,不能进行并行处理,所以会触发STW(全线暂停),停止所有的应用线程;这种GC算法不能充分利用多核CPU,不过有多少CPI内核,JVM在垃圾收集是都只能使用单个核心。
JDK版本: 在jdk1.3.1之前只有Serial
使用方式: -XX:+UseSerialGC

4.1 ParNew (并行GC)

ParNew (并行GC):它是Serial收集器的多线程版本,使用 mark-copy(标记-复制)算法。除了使用多条线程进行垃圾收集之外,其余行为包括Serial收集器可用的所有控制参数、收集算法、Stop The World、对象分配规则、回收策略等都与Serial收集器完全一样,可以配合CMS 使用。 ParNew适用于运行多CPU的环境下,单CPU环境Serial回收效率更高。
ParNew是新生代的垃圾回收器。配合CMS 使用;
使用方式: -XX:+UseParNewGC

4.2 Parallel Scavenge (并行 GC)

Java8默认使用 Parallel
Parallel Scavenge并行GC年轻代使用 mark-copy(标记-复制)算法,老年代使用 mark-sweep-compact(标记-清除-整理)算法; 并行垃圾收集器适用于多核服务器,主要目标是增加吞吐量。因为对系统资源的有效使用,能达到更高的吞吐量, 年轻代和老年代进行GC垃圾回收时都会触发STW事件。在GC期间所有CPU内核都在并行清除垃圾,所以STW时间更短。
JAVA8默认使用 并行GC
年轻代使用方式:-XX:+UseParallelGC
老年代使用方式:-XX:+ UseParallelOldGC
年轻代与老年代共同使用方式:-XX:+UseParallelGC -XX:+UseParallelOldGC

4.3 Concurrent Mark-Sweep ( 并发GC)

CMS作用于老年代,主要使用并发 mark-sweep(标记-清除)算法,SerialOld 作为备选方案 当放生Full GC是 就是使用 SerialOld 来GC的。
CMS的涉及目标是避免在老年代垃圾收集是出现长时间的卡顿,主要通过两种手段达成此目标:

  1. 不对老年代进行整理,使用free-lists(空闲列表)来管理内存空间的回收。
  2. 在mark-sweep(标记-清除)阶段的大部分工作和应用线程一起并发执行。

也就是说,在这些阶段没有明显的应用线程暂停,但值得注意的是,它仍然会跟应用线程争抢CPU的时间。默认情况下,CMS 使用的并发线程数等于CPU核心数的1/4。
如果服务器是多核CPU,并且主要调优目标是降低GC停顿导致的系统延迟,那么使用CMS是个很明智的选择。进行老年代的并发回收时,可能会伴随着多次年轻代的 minor GC。
使用方式:-XX+UseConcMarkSweepGC
CMS 会经历6个阶段 初始标记(STW)->并发标记->最终标记(STW)->并发清除->并发重置

4.4 G Frist(G1)

Java9默认使用G1
G1 GC 是一款面向服务器的垃圾收集器,主要针对配备多核处理器及大容量内存的机器,以极高概率满足GC停顿时间要求的同时,还具备高吞吐量性能特征。
G1的出现 堆不在分为年轻代跟老年代,而是换分为多个(通常为2048个)可以存放对象的小块堆区域(Smaller Heap Regions)。每一个小块(Region),可能一会被定义为Eden区,一会被指定为Survivor区或者被定义为Old区。这样的划分使得 G1 不必每次都去收集整个堆空间,而是以增量的方式来进行处理,每次只处理一部分内存块(Region)。保证了G1收集器在有限时间内可以尽可能高的收集效率。
G1 收集器在后台维护一个优先列表,每次根据允许的收集时间,优先选择回收价值最大的小块(Region)。这也是G1 名称的由来。
G1 的堆结构图

G1 GC 的处理步骤

  • 初始标记(initial mark,STW):在此阶段,G1 GC 对根进行标记。该阶段与常规的 (STW) 年轻代垃圾回收密切相关。
  • 并发标记(Concurrent Marking):G1 GC 在整个堆中查找可访问的(存活的)对象。
  • 最终标记(Remark,STW):该阶段是 STW 回收,帮助完成标记周期。
  • 筛选回收(Cleanup,STW):筛选回收阶段首先对各个Region的回收价值和成本进行排序,根据用户所期望的GC停顿时间来制定回收计划,这个阶段其实也可以做到与用户程序一起并发执行,但是因为只回收一部分Region,时间是用户可控制的,而且停顿用户线程将大幅提高收集效率。

G1 GC 的注意事项
特别需要注意的是,在某些情况下G1会触发Full GC,这个时候G1会退化使用Serial收集器来完成垃圾的回收工作。
触发Full GC 的场景

  • 并发模式失败: G1启动标记收齐,但在MixedGC 之前,老年代被填满,这个时候G1会放弃标记周期 触发Full GC。 解决办法: 增加堆大小或者调整周期(例如增加线程数 -XX:ConGCThreads等)。
  • 晋升失败: 没有足够的内存仅供存活对象或者晋升对象使用,会触发Full GC。 解决办法:增加 -XX:G1ReservePercent 现象的值 增加预留内存量,或者通过增加并行标记线程 -XX:ConcGCThreads
  • 巨型对象分配失败: 当巨型对象找不到合适的内存空间进行分配时,就会触发Full GC 来释放空间。 解决方法:增加Region大小 -XX:G1HeapRegionSize

使用方式:-XX:+UseG1GC -XX:MaxGCPauseMillis=50
这里 XX:MaxGCPauseMillis 为最长STW的预期值
G1的配置参数
在这里插入图片描述
在这里插入图片描述

4.5 ZGC

ZGC: 通过着色指针和读屏障,实现几乎全部的并发执行,几毫秒级别的延迟,线性可扩展;
使用方式:-XX:+UnlockExperimentalVMOptions -XX:+UseZGC -Xmx16g

4.6 Epsilon

Epsilon: 实验性GC,供性能分析使用;

4.7 Shenandoah GC

Shenandoah GC: G1的改进版本,跟ZGC类似

5. 总结

GC串行/并行/并发新生代/老年代算法目标默认版本适用场景
Serial串行新生代复制响应速度优先jdk1.3.1之前单CPU环境下的Client模式
SerialOld串行老年代标记-整理响应速度优先jdk1.3.1之前单CPU环境下的Client模式,CMS的备选方案
Parallel并行新生代复制高吞吐量jdk8 默认使用在后台运算而不需要太多交互任务,多CPU不注重响应速度的情况下
ParallelOld并行老年代标记-整理高吞吐量jdk8 默认使用在后台运算而不需要太多交互任务,多CPU不注重响应速度的情况下
ParNew并行新生代复制响应速度优先需要手动设置多CPU环境时在Server模式下与CMS配合使用
CMS并发老年代标记清除响应速度优先需要手动设置集中在互联网站或B/S系统服务端上的Java应用
G1并发堆空间变成region块标记-整理+复制响应速度优先jdk9 默认使用面向服务端应用,替换CMS, STW时间短

各个GC的常用组合

  • Serial + Serial Old 实现单线程的低延迟垃圾回收机制。
  • ParNew + CMS 实现多线程的低延迟垃圾回收机制。
  • Parallel Scavenge + Parallel Scavenge Old,实现多线程的高吞吐量垃圾回收机制。
    垃圾回收图

如何选择GC算法

  1. 如果系统考虑吞吐优先,CPU资源都用来最大程度处理业务,用Parallel。
  2. 如果系统考虑低延迟有限,每次GC时间尽量短,用CMS 。
  3. 如果系统内存堆较大 4G以上,同时希望整体来看平均GC时间可控,使用G1。

G1 对于内存大小的考量:

  1. 一般4G以上,算是比较大,用G1的性价比较高。
  2. 一般超过8G,比如16G-64G内存,非常推荐使用G1 GC

6. GC 面试题

6.1 CMS 与G1的异同

GC使用范围STW时间算法GC过程
cms老年代CMS收集器以最小的停顿时间为目标的收集器标记-清除初始标记->并发标记->重新标记->并发清除
G1新生代/老年代G1收集器可预测垃圾回收的停顿时间(建立可预测的停顿时间模型)标记-整理初始标记->并发标记->最终标记->筛选回收

6.2 Full GC 触发的场景

  • System.gc() 方法 此方法的调用是建议JVM进行Full GC 虽然只是建议,但是很多情况下他是会触发FullGC 从而增加Full GC的频率,即增加了STW的次数,建议在开发中不使用这种影响系统的方法,让虚拟机自己去管理他的内存, 可以通过-XX:+ DisableExplicitGC来禁止RMI(Java远程方法调用)调用System.gc。
  • 堆空间不足
  • 永久代空间不足
  • 对象晋升失败: 通过MinorGC 新生代对象 晋升为老年代大于 老年代的可用内存,会触发Full GC

6.3 怎么判断内存泄漏

6.4 CMS 的GC流程

初始标记(STW) -> 并发标记 -> 重新标记(STW) -> 并行清除(STW 采用标记清理算法)

6.5 ThreadLocal 有没有内存泄露的问题

6.6 GC调优 都怎么调优

6.7 G1 两个Region 不是连续的,而且之间还有可达的引用, 现在要回收一个, 另一个怎么处理

6.8 G1 GC的流程

初始标记(STW) -> 并发标记 -> 最终标记(STW) -> 筛选回收(标记复制 STW)

6.9 什么是Full GC

Full GC 是清理整个堆空间 - 老年代 年轻代 永久代(元数据区);
当使用G1 、 CMS 的时候,Full GC 是 Serial+SerialOld。
当使用 Parallel 的时候, Full GC 是使用 ParallNew+ ParallOld

6.10 G1 怎么做到预测STW 时间的

G1的堆内存是多个region块, 在垃圾回收时不是整代回收,而是回收部分region块。G1 后台会维护一个优先列表,在预测时间内,优先选择回收价值最大的Region块来进行回收,来保证在有限时间内垃圾回收尽可能高的效率。这一步是在GC流程 第四步 筛选回收的时候进行 预测STW时间的.

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/煮酒与君饮/article/detail/887949
推荐阅读
相关标签
  

闽ICP备14008679号