JVM整理(二)
垃圾回收
1. 如何判断对象可以回收
2. 垃圾回收算法
3. 分代垃圾回收
4. 垃圾回收器
5. 垃圾回收调优
1. 如何判断对象可以回收
1.1引用计数器
如个这个对象被其他对象引用的,那么就+1 。存在问题:循环依赖
1.2 可达性分析算法
-
Java 虚拟机中的垃圾回收器采用可达性分析来探索所有存活的对象
-
扫描堆中的对象,看是否能够沿着 GC Root对象 为起点的引用链找到该对象,找不到,表示可以回收
- 肯定不可能当成垃圾的对象可以作为GC Root
1.3四种引用
1. 强引用
- 只有所有 GC Roots 对象都不通过【强引用】引用该对象,该对象才能被垃圾回收
2. 软引用(SoftReference)
- 仅有软引用引用该对象时,在垃圾回收后,内存仍不足时会再次出发垃圾回收,回收软引用对象
- 可以配合引用队列来释放软引用自身
3. 弱引用(WeakReference)
- 仅有弱引用引用该对象时,在垃圾回收时,无论内存是否充足,都会回收弱引用对象
- 可以配合引用队列来释放弱引用自身
4. 虚引用(PhantomReference)
- 必须配合引用队列使用,主要配合 ByteBuffffer 使用,被引用对象回收时,会将虚引用入队,由 Reference Handler 线程调用虚引用相关方法释放直接内存
5. 终结器引用(FinalReference)
- 无需手动编码,但其内部配合引用队列使用,在垃圾回收时,终结器引用入队(被引用对象暂时没有被回收),再由 Finalizer 线程通过终结器引用找到被引用对象并调用它的 fifinalize方法,第二次 GC 时才能回收被引用对象
2、垃圾回收算法
2.1标记清除(Mark Sweep)
- 速度较快
- 会造成内存碎片
2.2标记整理(Mark Compact)
- 速度慢
- 没有内存碎片
2.3复制(Copy)
- 不会有内存碎片
- 需要双倍的内存空间
3、 分代垃圾回收
-
对象首先分配在伊甸园区域
- 新生代空间不足,触发minor gc ,伊甸园和from存活的对象使用copy复制到to中,存活的对象年龄+1并且交换from to
-
minor gc 会引发 stop the world(STW),暂停其它用户的线程,等垃圾回收结束,用户线程才恢复运行
-
当对象寿命超过阈值时,会晋升至老年代,最大寿命是15(4bit)
-
当老年代空间不足,会先尝试触发 minor gc,如果之后空间仍不足,那么触发 full gc,STW的时间更长
细节:大对象在新生代空间不够的情况下,会直接晋升到老年代
4、垃圾回收器
1.串行
- 单线程
- 对内存较小,适合个人电脑
2.吞吐量优先
- 多线程
- 堆内存较大,多核cpu
-
让单位时间内,STW 的时间最短 0.2 0.2 = 0.4,垃圾回收时间占比最低,这样就称吞吐量高
3.响应时间优先
-
多线程
-
堆内存较大,多核 cpu
-
尽可能让单次 STW 的时间最短 0.1 0.1 0.1 0.1 0.1 = 0.5
4.1串行
-XX:+UseSerialGC = Serial + SerialOld
新生代复制算法 老年代标记整理算法
4.2吞吐量优先
并行(并行是指两个或者多个事件在同一时刻发生)
4.3 响应时间优先(CMS)
并发(并发是指两个或多个事件在同一时间间隔发生)
XX:+UseConcMarkSweepGC ~ -XX:+UseParNewGC ~SerialOld
并发标记清除 复制算法 如果并发失败,会退化到串行
工作在老年代 工作在新生代
-XX:ParallelGCThreads=n ~ -XX:ConcGCThreads=threads
并行垃圾回收器 并发垃圾回收器
-XX:CMSInitiatingOccupancyFraction=percent
-XX:+CMSScavengeBeforeRemark
在重新标记前清理一次新生代
初始标记:只标记一些GC Root根对象,STW非常短
并发标记:没有STW
重新标记:有STW
注:响应时间 优先在并发清理的时候,其他线程在运行时可能又会产生新的垃圾(浮动垃圾),只会在第二次GC才会被清理
对整个应用程序的吞吐量有一定影响
4.4 G1(Garbage First)
适用场景
- 同时注重吞吐量(Throughput)和低延迟(Low latency),默认的暂停目标是 200 ms
- 超大堆内存,会将堆划分为多个大小相等的 Region
- 整体上是 标记+整理 算法,两个区域之间是 复制 算法
1) G1 垃圾回收阶段
1、Young Collection
会STW,就是一个普通的分代垃圾回收
2、Young Collection + CM
- 在 Young GC 时会进行 GC Root 的初始标记
- 老年代占用堆空间比例达到阈值时,进行并发标记(不会 STW),由下面的 JVM 参数决定
-XX:InitiatingHeapOccupancyPercent=percent (默认45%)
3、Mixed Collection
会对 E、S、O 进行全面垃圾回收
- 最终标记(Remark)会 STW
- 拷贝存活(Evacuation)会 STW
-XX:MaxGCPauseMillis=ms

有选择的收集老年代,垃圾最多的老年代区
2)Full GC
- SerialGC
新生代内存不足发生的垃圾收集 - minor gc
老年代内存不足发生的垃圾收集 - full gc
- ParallelGC
新生代内存不足发生的垃圾收集 - minor gc
老年代内存不足发生的垃圾收集 - full gc
- CMS
新生代内存不足发生的垃圾收集 - minor gc
老年代内存不足
- G1
新生代内存不足发生的垃圾收集 - minor gc
老年代内存不足
CMS和G1有两种情况 :
G1为例:
老年代内存与整个堆内存占比达到某个阈值,就会触发并发标记和混合收集阶段
如果垃圾回收速度比产生快,不会触发full gc ,否则触发
3)Young Collection 跨代引用
-
新生代回收的跨代引用(老年代引用新生代)问题
-
卡表与 Remembered Set
-
在引用变更时通过 post-write barrier + dirty card queue
-
concurrent refinement threads 更新 Remembered Set
在进行对象引用创建时,会有一个查找过程,查找引用是否被其他区域对象所引用若是,则在RSet中标注,也就是脏卡
避免遍历整个老年代去查找新生代的引用
4)Remark
重标记
5)JDK 8u20 字符串去重
6)JDK 8u40 并发标记类卸载
所有对象都经过并发标记后,就能知道哪些类不再被使用,当一个类加载器的所有类都不再使用,则卸载它所加载的所有类
7)JDK 8u60 回收巨型对象
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异