面试官:聊聊 G1,你清楚 G1 的特性吗?
天生适合于大内存机器!为什么这么说,就是因为 G1 是可以控制 GC 停顿时间的,那么比如说对于 Kafka 类似的高并发消息中间件,一般来说都需要大内存机器部署,比如 64G,那么可以给年轻代 30G 内存来存放对象
欢迎关注公众号(通过文章导读关注:【11来了】),及时收到 AI 前沿项目工具及新技术的推送!
在我后台回复 「资料」 可领取
编程高频电子书
!
在我后台回复「面试」可领取硬核面试笔记
!文章导读地址:点击查看文章导读!
感谢你的关注!
G1:区域化分代式
G1(Garbage-First)垃圾收集器是在 Java7 update4 之后引入的一个新的垃圾收集器,它开创了收集器面向局部收集的设计思路和基于 Region 的内存布局形式
G1 最大的 特点 就是 满足 GC 停顿时间的同时,还具备高吞吐量的性能特征
-
G1的出现就是为了适应
不断扩大的内存和不断增加的处理器数量
,进一步降低暂停时间,同时兼顾良好的吞吐量 -
G1是一款面向服务端应用的垃圾收集器,主要针对
配备多核CPU以及大容量内存的机器
,兼顾了低GC停顿时间和高吞吐量 -
在 JDK1.7 正式启用,是 JDK 9以后的默认垃圾收集器,取代了 CMS 以及 Parallel+Parallel Old 的组合,被 Oracle 官方称为“全功能的垃圾收集器”
G1 最显著的特点:
天生适合于大内存机器!
为什么这么说,就是因为 G1 是可以控制 GC 停顿时间的,那么比如说对于 Kafka 类似的高并发消息中间件,一般来说都需要大内存机器部署,比如 64G,那么可以给年轻代 30G 内存来存放对象
但是由于内存太大,达到 30G,那么它的 GC 肯定不会几十毫秒就结束了,可能要几秒钟才可以 GC 完成,那几秒钟的卡顿时间对用户感知还是比较明显的,而且 Kafka 作为高并发的消息中间件,可能没多长时间,几分钟就会将内存占满,导致频繁 GC
那么使用了 G1 之后,我们可以 设置期望的 GC 停顿时间
,比如设置为 50ms(-XX:MaxGCPauseMillis=50)
,那么这对于用户来说就几乎没有感知
因此说,G1 天生适合于大内存机器!
G1 中区域的划分
G1 是将 JVM 堆内存划分为了多个 Region
,也就是多个相同大小的区域,默认 Region 的大小是堆内存的 1/2048,因此如果设置堆内存大小为 4096MB,那么每个 Region 的大小为 2M
在 G1 中年轻代和老年代都是一多个 Region 的集合,并且 Region 的区域会动态变化,也就是一个 Region 本来是年轻代,GC 之后,可能会变为老年代
G1 中对大对象的优化
在G1中,有一种特殊的区域叫 Humongous
区域
- 如果一个对象占用的空间超过了分区容量 50% 以上,G1 收集器就认为这是一个巨型对象。 这些巨型对象,默认直接会被分配在老年代
- 但是,如果是一个短期存在的巨型对象,在分区之间来回拷贝,就会对垃圾收集器造成负面影响。为了解决这个问题,G1 划分了 Humongous 区,它用来专门存放巨型对象。如果一个 H 区装不下一个巨型对象,那么 G1 会寻找连续的 H 分区来存储,从而避免大对象进入老年代占用大量空间,导致 full gc 带来的性能开销!
G1 的 GC 过程
-
初始标记:标记一下 GC Roots 能直接关联到的对象,需要停顿用户线程,但耗时很短
-
并发标记:是从 GC Roots 开始对堆中对象进行可达性分析,找出存活的对象,这阶段耗时较长,但可与用户程序并发执行
-
最终标记:修正在并发标记期间因用户程序继续运作而导致标记产生变动的那一部分标记记录
-
筛选回收:对各个 Region 的回收价值和成本进行排序,根据用户所期望的 GC 停顿时间来制定回收计划
G1 的回收算法主要使用 复制算法
,将存活对象从一个 Region 复制到另一个 Region,再清空原 Region
并且 G1 会维护一个 优先列表
,会在允许的停顿时间之内,尽可能回收价值更大的 Region,尽可能提升回收效率!
为什么叫做 Garbage First 呢?
- Garbage First 也就是垃圾优先,G1 是一个并行回收器,将堆内存分割为多个不相关区域,称为 Region,使用不同的 Region 来表示 Eden、Survivor0、Survivor1、老年代等
- G1有计划地避免在整个 Java 堆中进行全区域的垃圾收集,G1跟踪各个Region的垃圾堆积的价值大小,在后台维护一个优先级列表,每次根据允许的收集时间,优先回收价值最大的Region,G1侧重于回收垃圾最大量的区间,因此称之为Garbage-First 垃圾优先
G1 应用场景
- 服务端应用,针对具有大内存、多核处理器的机器
- 最主要的应用是需要低 GC 延迟、并且具有大堆的应用程序
- HotSpot 除了 G1,其他的垃圾收集器使用内置的 JVM 线程执行 GC 的多线程操作,而 G1 采用应用线程承担后台运行的 GC 工作,即当 JVM 的 GC 线程处理速度慢时,系统会调用应用程序线程帮助加速垃圾回收过程
G1 相关参数:
# 使用 G1 垃圾收集器
-XX:+UseG1GC
# 设置期望达到的最大GC停顿时间指标(JVM会尽力实现,但不保证达到),默认值是 200 毫秒。
-XX:MaxGCPauseMillis=
# 设置的 G1 区域的大小。值是 2 的幂,范围是 1 MB 到 32 MB 之间。
# 目标是根据最小的 Java 堆大小划分出约 2048 个区域。
# 默认是堆内存的 1/2000。
-XX:G1HeapRegionSize=n
# 设置并行垃圾回收线程数,一般将n的值设置为逻辑处理器的数量,建议最多为8。
-XX:ParallelGCThreads=n
# 设置并行标记的线程数。将n设置为ParallelGCThreads的1/4左右。
-XX:ConcGCThreads=n
# 设置触发标记周期的 Java 堆占用率阈值。默认占用率是整个 Java 堆的 45%。
-XX:InitiatingHeapOccupancyPercent=n
优势
并行与并发
- 并行:G1 在回收期间,可以有多个 GC 线程同时工作,此时用户线程 STW
- 并发:G1 部分工作可以和应用程序同时执行
分代收集
- G1 将堆空间分为若干个区域 Region,这些区域包含了逻辑上的新生代和老年代
- 之前的垃圾收集器要么工作在新生代,要么工作在老年代,而 G1 同时
兼顾了新生代和老年代
空间整合
- G1 将堆内存划分为若干 Region,内存回收以 Region 为单位,Region 之间是
复制算法
,整体上可以看作是标记-压缩算法
,两种算法都可以避免出现内存碎片
- G1 将堆内存划分为若干 Region,内存回收以 Region 为单位,Region 之间是
可预测的停顿时间模型
- G1 除了追求低停顿外,还能建立可预测的停顿时间模型,能让使用者明确指定在一个长度为M毫秒的时间片段内,消耗在垃圾收集上的时间不超过N毫秒
更多推荐
所有评论(0)