1. 分类及触发条件⭐️🔴

1.1. 堆分区及对应 GC

性能调优-进阶-1、JVM-GC调优

1.2. Minor GC(YGC)


%%
1827-🏡⭐️◼️新生代 GC 的特点是什么?新生代分为 Eden,S0,S1,Eden 满了就发生 YGC,新生代 GC 是非常频繁的,Survivor 区满了不会发生 GC,是被动 GC。YGC 会引发短时间的 STW◼️⭐️-point-202301281827%%

image.png

1.3. Major GC(Old GC)

1.4. Full GC⭐️🔴

1.4.1. System.gc() 方法的调用

此方法的调用是建议 JVM 进行 Full GC, 虽然只是建议而非一定, 但很多情况下它会触发 Full GC, 从而增加 Full GC 的频率, 也即增加了间歇性停顿的次数。强烈影响系建议能不使用此方法就别使用,让虚拟机自己去管理它的内存,可通过通过 -XX:+ DisableExplicitGC 来禁止 RMI 调用 System.gc。

1.4.2. 老年代代空间不足

老年代空间只有在新生代对象转入及创建为大对象、大数组时才会出现不足的现象,当执行 Full GC 后空间仍然不足,则抛出如下错误:
java.lang.OutOfMemoryError: Java heap space
为避免以上两种状况引起的 Full GC,调优时应尽量做到让对象在 Minor GC 阶段被回收、让对象在新生代多存活一段时间;不要创建过大的对象及数组。 ^0m8k82

1.4.3. 方法区空间不足

JVM 规范中运行时数据区域中的方法区,在 HotSpot 虚拟机中又被习惯称为永生代或者永生区,Permanet Generation 中存放的为一些 class 的信息、常量、静态变量等数据,当系统中要 加载的类、反射的类和调用的方法较多 时,Permanet Generation 可能会被占满,在未配置为采用 CMS GC 的情况下也会执行 Full GC。如果经过 Full GC 仍然回收不了,那么 JVM 会抛出如下错误信息:
java.lang.OutOfMemoryError: PermGen space
为避免 Perm Gen 占满造成 Full GC 现象,可采用的方法为增大 Perm Gen 空间或转为使用 CMS GC。

1.4.4. CMS GC 时出现 promotion failed 和 concurrent mode failure

对于采用 CMS 进行老年代 GC 的程序而言,尤其要注意 GC 日志中是否有 promotion failed 和 concurrent mode failure 两种状况,当这两种状况出现时可能会触发 Full GC。

promotion failed 是在进行 Minor GC 时,survivor space 放不下、对象只能放入老年代,而此时老年代也放不下造成的
concurrent mode failure 是在执行 CMS GC 的过程中同时有对象要放入老年代,而此时老年代空间不足造成的(有时候“空间不足”是 CMS GC 时当前的浮动垃圾过多导致暂时性的空间不足触发 Full GC)。
应对措施为:增大 survivor space、老年代空间或调低触发并发 GC 的比率,但在 JDK 5.0+、6.0+ 的版本中有可能会由于 JDK 的 bug29 导致 CMS 在 remark 完毕后很久才触发 sweeping 动作。对于这种状况,可通过设置 -XX: CMSMaxAbortablePrecleanTime=5(单位为 ms)来避免。

1.4.5. Minor GC 晋升到老年代的平均大小大于老年代的剩余空间

这是一个较为复杂的触发情况,Hotspot 为了避免由于新生代对象晋升到老年代导致老年代空间不足的现象,在进行 Minor GC 时,做了一个判断,如果之前统计所得到的 Minor GC 晋升到老年代的平均大小大于老年代的剩余空间,那么就直接触发 Full GC。

例如程序第一次触发 Minor GC 后,有 6MB 的对象晋升到老年代,那么当下一次 Minor GC 发生时,首先检查老年代的剩余空间是否大于 6MB,如果小于 6MB,则执行 Full GC。

当新生代采用 PS GC 时,方式稍有不同,PS GC 是在 Minor GC 后也会检查,例如上面的例子中第一次 Minor GC 后,PS GC 会检查此时老年代的剩余空间是否大于 6MB,如小于,则触发对老年代的回收。

除了以上 4 种状况外,对于使用 RMI 来进行 RPC 或管理的 Sun JDK 应用而言,默认情况下会一小时执行一次 Full GC。可通过在启动时通过 - java -Dsun.rmi.dgc.client.gcInterval=3600000 来设置 Full GC 执行的间隔时间或通过 -XX:+ DisableExplicitGC 来禁止 RMI 调用 System.gc。

注意这种情况与动态年龄判断的区分:一个是触发 fullGC,一个是触发晋升到老年代

性能调优专题-基础-4、JVM-堆和GC理论

6、堆中分配很大的对象

所谓大对象,是指需要大量连续内存空间的 java 对象,例如很长的数组,此种对象会直接进入老年代,而老年代虽然有很大的剩余空间,但是无法找到足够大的连续空间来分配给当前对象,此种情况就会触发 JVM 进行 Full GC。

为了解决这个问题,CMS 垃圾收集器提供了一个可配置的参数,即 -XX:+UseCMSCompactAtFullCollection 开关参数,用于在“享受”完 Full GC 服务之后额外免费赠送一个碎片整理的过程,内存整理的过程无法并发的,空间碎片问题没有了,但停顿时间不得不变长了,JVM 设计者们还提供了另外一个参数 -XX:CMSFullGCsBeforeCompaction, 这个参数用于设置在执行多少次不压缩的 Full GC 后, 跟着来一次带压缩的。

原文链接: https://blog.csdn.net/chenleixing/article/details/46706039

image.png

2. 内存分配过程⭐️🔴

  1. new 的对 象先放伊甸园区。此区有大小限制。
  2. 当伊甸园的空间填满时,程序又需要创建对象,JVM 的垃圾回收器将对伊甸园区进行垃圾回收(MinorGC),将伊甸园区中的不再被其他对象所引用的对象进行销毁。再加载新的对象放到伊甸园区
  3. 然后将伊甸园中的剩余对象移动到幸存者 0 区。
  4. 如果再次触发垃圾回收,此时上次幸存下来的放到幸存者 0 区的,如果没有回收,就会放到幸存者 1 区。
  5. 如果再次经历垃圾回收,此时会重新放回幸存者 0 区,接着再去幸存者 1 区。
  6. 啥时候能去养老区呢?可以设置次数。默认是 15 次。
  1. 在养老区,相对悠闲。当养老区内存不足时,再次触发 GC:Major GC,进行养老区的内存清理
  2. 若养老区执行了 Major GC 之后,发现依然无法进行对象的保存,就会产生 OOM 异常。

2.1. 流程图

2.2. 总结

  • 针对幸存者 s0,s1 区的总结:复制之后有交换,谁空谁是 to
  • 关于垃圾回收:频繁在新生区收集,很少在老年代收集,几乎不在永久代和元空间进行收集

2.3. 为什么是 15 次⭐️🔴

对象头中的分代年龄,用于分代 GC。分代 GC 我们在后面的章节会详细讲述,这里只是看一些特性。

记录分代年龄一共 4 bit,所以最大为 2^4 - 1 = 15。所以配置最大分代年龄 -XX:MaxTenuringThreshold=n 这个 n 不能大于 15,当然也不能小于 0.等于 0 的话,就直接入老年代。等于 16 的话,就是从不进入老年代,这样不符合 JVM 规范,所以不能大于 15。默认是 15。

3. 内存分配策略⭐️🔴

如果对象在 Eden 出生并经过第一次 Minor GC 后仍然存活,并且能被 Survivor 容纳的话,将被移动到 survivor 空间中,并将对象年龄设为 1。对象在 survivor 区中每熬过一次 MinorGC,年龄就增加 1 岁,当它的年龄增加到一定程度(默认为 15 岁,其实每个 JVM、每个 GC 都有所不同)时,就会被晋升到老年代 ❕%%
1306-🏡⭐️◼️对象年龄是如何开始计算的?🔜📝 对象在 Eden 创建之后,经过第一次 YGC 还存活并且能够在 Survivor 中放得下,那么进入 Survivor 之后年龄设置为 1,每经过一次 YGC 年龄就 +1◼️⭐️-point-202301301306%%

对象晋升老年代的年龄阀值,可以通过选项 -XX:MaxTenuringThreshold 来设置

针对不同年龄段的对象分配原则如下所示:

  1. 优先分配到 Eden
  2. 大对象直接分配到老年代(尽量避免程序中出现过多的大对象)
  3. 长期存活的对象分配到老年代
  4. 动态对象年龄判断:如果 survivor 区中【相同年龄的】所有对象大小的总和大于 Survivor 空间的一半,年龄大于或等于该年龄的对象可以直接进入老年代,无须等到 MaxTenuringThreshold 中要求的年龄。 ^eblx0q
  5. 空间分配担保: -XX:HandlePromotionFailure

4. GC 作用域

image-20200322225622428

5. 垃圾判断

https://www.bilibili.com/video/av75859780?p=951

image-20200322233137394

5.1. GC roots⭐️🔴

5.1.1. 查询位置

%%
0829-🏡⭐️◼️GCroot 的查询位置有什么🔜MSTM📝 1. 虚拟机栈中本地变量表中引用的对象;2. 方法区中静态变量引用的对象;3. 方法区中常量引用的对象;4. 本地方法栈中 JNI 引用的对象◼️⭐️-point-202301310829%%

image-20200322233601844

image-20200322234212539

性能调优专题-基础-5、JVM-虚拟机栈

5.1.2. 包含类型⭐️🔴

%%
▶16.🏡⭐️◼️【🌈费曼无敌🌈⭐️第一步⭐️】◼️⭐️-point-20230305-1507%%
❕ ^605ynj


%%
1300-🏡⭐️◼️GCroot 包含类型🔜MSTM📝 1. 虚拟机栈中局部变量表中引用的对象;2. 方法区中静态变量、常量引用的对象;3. 本地方法栈中引用的对象;4.synchronized 引用的对象,即锁对象;5.JVM 内部引用对象,比如基本数据类型对应的 Class 对象、系统类加载器、异常对象;6. 反映虚拟机内部情况的 JMXBean、JVMTI 注册的回调、本地代码缓存◼️⭐️-point-202302011300%%

无论 G1 还是其他分代收集器,JVM 都是使用 Remembered Set 来避免全局扫描,每个 region 的记忆集 (Remembered Set) 也是 GC Root 的查找范围。 ^nvygi7

5.2. 三色标记

%%
▶31.🏡⭐️◼️【🌈费曼无敌🌈⭐️♨️♨️♨️⭐️】◼️⭐️-point-20230310-1706%%
❕ ^tw0udc

性能调优-基础-12、GC-三色标记算法

5.3. 分析工具

5.3.1. GC 日志分析

https://www.bilibili.com/video/BV1MJ411E7V4?p=77&vd_source=c5b2d0d7bc377c0c35dbc251d95cf204

image.png

image.png

image.png

image-20200323011750780

5.3.2. 统一日志管理

image.png

5.3.3. MAT

image-20200131104247666

image-20200131104312174

image-20200131104344365

image-20200131104540890

image-20200131104616396

image-20200131104709994

5.4. 四种引用

image-20200131105211811

实线表示强引用,强引用:沿着 gc root 对象可达的对象的引用

image-20200131105311476

image-20200131105548453

5.4.1. 架构

image-20200323085705810

5.4.2. 强引用

image-20200323085831208

5.4.3. 软引用

image-20200323090016016

image-20200323094300109

5.4.4. 弱引用

image-20200323094047025

image-20200323090612301

image-20200323095627811

5.4.5. 虚引用

主要做对象回收的监控

image-20200323094547003

image-20200323095910530

image-20200410090348591

5.4.6. 应用场景⭐️🔴

5.4.6.1. 软引用-图片缓存

%%
▶17.🏡⭐️◼️【🌈费曼无敌🌈⭐️第一步⭐️】◼️⭐️-point-20230305-1510%%
❕ ^i773fb

image-20200323091024695

软引用的回收

image-20200401221308306

5.4.6.2. 弱引用 -ThreadLocal⭐️🔴

并发基础-18、ThreadLocal

5.4.6.3. 虚引用 -directByteBuffer 释放直接内存⭐️🔴

image-20200401211253916

image-20200401181607451

分析:

当 DirectByteBuffer 被垃圾回收后,虚引用会被放到引用队列中,线程 ReferenceHandler 会通过调用 cleaner 的 clean 方法,调用 Unsafe.freeMemmory 方法,从而完成堆外内存的回收。

5.4.7. WeakHashMap

image-20200323100241365

有 GC 就清空,适用于高速缓存和内存敏感相关应用的开发

5.4.8. 总结

image-20200323100135004

6. 垃圾回收

6.1. 常见算法

6.1.1. 引用计数

image-20200322230252844

6.1.2. 复制

image-20200322230521859

image-20200322230451410

6.1.3. 标记清除

6.1.4. 标记整理

6.1.5. 对比

6.2. 回收过程

image-20200131121029469

6.3. 参数设置

https://www.bilibili.com/video/BV1yE411Z7AP?p=64

image-20200131121103656

6.4. 4 大回收策略思想

6.4.1. 串行

新生代用复制,老年代用标记 - 整理算法

image-20200131134408499

6.4.2. 并行

新生代用复制算法,老年代用标记 - 整理算法

会暂停用户进程

image-20200131134328362

6.4.3. 并发

基于标记 - 清除垃圾回收算法的回收器

不会暂停用户进程

image-20200131134512431

6.4.4. G1- 区域化分代式

区域化分代式

6.4.5. 并发与并行区别

6.5. 七大垃圾回收器

性能调优-基础-11、7大垃圾回收器

6.6. GC 调优

性能调优-进阶-1、JVM-GC调优

7. 参考与感谢

❕ ^7fgp3j

7.1. 尚硅谷雷丰阳

%%
▶12.🏡⭐️◼️【🌈费曼无敌🌈⭐️第一步⭐️】◼️⭐️%%
❕ ^uwx6yh

7.1.1. 视频

https://www.bilibili.com/video/BV1PJ411n7xZ?p=57&vd_source=c5b2d0d7bc377c0c35dbc251d95cf204

7.1.2. 资料

已下载:/Users/Enterprise/0003-Architecture/011-Java/尚硅谷/JVM 上篇:内存与垃圾回收篇

对象创建-7、JVM-堆
1
/Users/taylor/Nutstore Files/Obsidian_data/pages/002-schdule/001-Arch/001-Subject/013-DemoCode/brain-mapping/docs/宋老师讲的JVM课程视频课件脑图(下篇)
1
/Users/taylor/Nutstore Files/Obsidian_data/pages/002-schdule/001-Arch/001-Subject/013-DemoCode/NOTE_JVM/JVM下篇:性能监控与调优篇

7.2. 黑马程序员

7.2.1. 视频

https://www.bilibili.com/video/BV1yE411Z7AP/?spm_id_from=..search-card.all.click&vd_source=c5b2d0d7bc377c0c35dbc251d95cf204

7.2.2. 资料

已下载:

1
/Users/taylor/Nutstore Files/Obsidian_data/pages/002-schdule/001-Arch/001-Subject/007-性能调优专题/001-JVM/黑马程序员JVM完整教程

7.3. 马士兵

https://www.bilibili.com/video/BV1fi4y1U76z?p=21&vd_source=c5b2d0d7bc377c0c35dbc251d95cf204

7.4. 网络笔记

https://www.yuque.com/u21195183/jvm/lep6m9