JVM基础及垃圾回收

一、常用JVM参数

-Xms: 初始堆大小
-Xmx: 最大堆
-Xmn: 新生代大小
-Xss: 栈容量 -PermSize: 方法区大小 -MaxPermSize: 最大方法区大小 -MaxDirectMemorySize: 最大直接内存大小

二、java虚拟机基本结构

 

1.PC寄存器(程序计数器):线程私有的,记录的是正在执行的虚拟机字节码指令的地址。

2.java栈(虚拟机栈):线程私有的,每个方法在执行的同时都会创建一个栈帧,用于存储局部变量表、操作数栈、动态链接、方法出口等信息。方法的调用到完成对应入栈到出栈的过程。

3.本地方法栈:线程私有的,为native方法服务。

4.java堆:线程共享的,用于存放对象实例。从内存回收的角度看,分为新生代(eden、from、to)和老年代;从内存分配的角度看,java堆中可能划分出多个线程私有的分配缓冲区(TLAB)。

5.方法区(永久代):线程共享的,用于存储类信息、常量、静态变量、即时编译器编译后的代码等数据。GC行为比较少,主要针对常量池的回收和对类型的卸载。

5.1 运行时常量池:是方法区的一部分,用于存放编译期生成的字面量和符号引用。

6.直接内存:不受java堆大小的限制,直接申请系统的物理内存。

 

三、垃圾回收策略

主要针对堆区进行回收,方法区收集效率很低。

3.1 垃圾收集算法

3.1.1 标记-清除算法

主要用于老年代,首先标记出所有需要回收的对象,然后统一回收。
优点:简单
缺点:标记和清除的效率都不高,而且会产生大量的内存碎片。

3.1.2 复制算法

将内存分为大小相等的两块,每次只使用一块。当这一块内存用完了,就把存活的对象复制到另一块上,然后清除这一块。
主要用于新生代,把新生代按8:1:1的比例分,edan区分80%,from存活区和to存活区分10%。回收时,将edan和from(to)中存活的对象一次性复制到to(from)中,
然后清理掉,如果存活区空间不足,就分配到老年代。

3.1.3 标记-整理算法

主要用于老年代,标记过程与“标记-清除”算法一样,为解决内存碎片的问题,后续步骤不是直接对可回收对象进行清理,而是让所有存活的对象都像一端移动,
然后直接清理掉端边界以外的内存。

3.2 垃圾收集器

3.2.1 Serial(串行)收集器

单线程,串行,用于新生代,使用复制算法,运行在Client模式下。
优点:简单高效。缺点:它进行垃圾回收时,必须暂停其他所有的工作线程,直到收集结束。

3.2.2 Serial Old收集器

单线程,串行,用于老年代,使用标记整理算法,运行在Client模式下。
优点:简单高效。缺点:它进行垃圾回收时,必须暂停其他所有的工作线程,直到收集结束。
如果在Server模式下,它可以和Parallel Scavenge收集器搭配使用;还可以作为CMS收集器的后备预案,在并发收集发生Concurrent Model Failure 时使用。

3.2.3 ParNew收集器

用于新生代,其实就是Serial的多线程版本,它第一次实现了让垃圾收集线程和用户线程(基本上)同时工作,运行在Server模式下。但在单CPU环境下不如Serial。

3.2.4 Parallel(并行) Scavenge(打扫)收集器

用于新生代,使用复制算法,多线程,和ParNew类似。但是它的关注点是吞吐量【吞吐量=运行用户代码时间/(运行用户代码时间+垃圾收集时间)】,
其他收集器的关注点是缩短垃圾收集时用户线程的停顿时间。-XX:MaxGCPauseMillis控制最大垃圾收集停顿时间,-XX:GCTimeRatio设置吞吐量的大小

3.2.5 Parallel Old收集器

是 Parallel Scavenge收集器的老年代版本,多线程,使用“标记-整理”算法。
在注重吞吐量以及CPU资源敏感的场合,可以优先考虑Parallel Scavenge和Parallel Old搭配使用。

3.2.6 CMS收集器

目的是获取最短回收停顿时间 ,使用标记-清除算法。运作过程分为1.初始标记(STW);2.并发标记;3.重新标记(STW);4.并发清除。
优点:并发收集、低停顿
缺点:
1.因为是并发设计的,所以当CPU不足时,效率会不高;
2.由于并发清理阶段,用户线程还在产生垃圾,所以在jdk1.5中,CMS在老年代使用了68%时被激活,jdk1.6中,是92%。要是CMS运行期间内存不足,就会出现“Concurrent Mode Failure”失败,这时虚拟机会启用Serial Old来重新收集,这样停顿时间会更长了。
3. 因为是基于“标记-清除”算法,会有大量空间碎片。为了解决这个问题,CMS提供了碎片合并整理过程,但停顿时间更长了。

3.2.7 G1收集器

G1是一款面向服务端应用的垃圾收集器。
特点:并发和并行、分代收集、空间整合、可预测的停顿
运作步骤:初始标记、并发标记、最终标记、筛选回收
使用G1时,它将整个java堆划分为多个大小相等的独立区域(Region),新生代和老年代不再是物理隔离了,他们都是一部分Region的集合。
G1跟踪各个Region里面的垃圾堆积的价值大小,优先回收价值最大的Region。 jdk7 默认Parallel Scavenge(新生代)
+ Parallel Old(老年代) jdk8 默认Parallel Scavenge(新生代)+ Parallel Old(老年代) jdk9 默认G1 -XX:+PrintCommandLineFlagsjvm参数可查看默认设置收集器类型 -XX:+PrintGCDetails可通过打印的GC日志的新生代、老年代名称判断

四、内存分配

1.对象优先在Eden分配,当eden内存不足时,系统会发起一次Minor GC。经过一轮GC 后,对象会进入Survivor区,当Survivor区不足时,对象会直接分配到老年代。
2.大对象直接进入老年代。
3.长期存活的对象将进入老年代。在新生代,每经过一次GC,对象的年龄就加1,当加到15(默认值)时,就进入老年代。

五、G1 vs ZGC

G1:将新生代/老年代划分为多个Region,过程如下:Young GC → 并发标记 → Mixed GC → 循环往复

  • Young GC(年轻代标记回收):标记存活对象(短暂STW),将存活对象复制到Survivor或Old区,然后清空该Region
  • 并发标记(老年代标记):老年代到达45%,启动并发标记。完成后会进行最终标记(这一步存在STW)处理并发期间的变动(如新增对象、引用修改)。会使用读屏障处理对象引用变化
  • Mixed GC(混合回收年轻代+老年代):选择垃圾最多的Region,使用复制算法进行回收

ZGC:

STW:Stop The World

读屏障:

着色指针:

 

特性 G1 (Garbage-First) ZGC (Z Garbage Collector)
引入版本 JDK 7u4(JDK 9 成为默认) JDK 11(实验性),JDK 15 起生产可用
设计目标 平衡吞吐量与停顿时间,适用于大堆 极低停顿时间(<10ms),支持超大堆
最大停顿时间 可配置(默认约 200ms),但随堆增长可能上升 极低且稳定(通常 < 10ms),基本不受堆大小影响
停顿阶段(STW) Young GC 和 Mixed GC 期间有明显 STW 初始标记和最终转移阶段有极短 STW,其他阶段并发
并发性 部分并发(如并发标记),但 Young/Mixed GC 仍需 STW 高度并发:标记、清理、重定位均并发执行
堆内存支持 适合大堆(几十GB 到 TB 级) 支持超大堆(可达数 TB)
内存开销 约 5%~10% 约 15%~20%(因着色指针等元数据)
算法基础 分代 + Region + 标记-清除 + 复制 分代(可选)+ Region + 并发标记-整理
是否压缩/整理 Mixed GC 时进行部分压缩,减少碎片 并发重定位,主动整理内存,避免碎片
着色指针(Colored Pointers) ❌ 不使用 ✅ 使用(将 GC 信息编码在指针中)
读屏障(Load Barrier) ✅ 使用(用于并发标记) ✅ 使用(用于并发重定位和标记)
NUMA 支持 ❌ 不支持 ✅ 支持(可优化多插槽服务器性能)
适用场景 一般大型服务、对停顿有一定要求的应用 对延迟极度敏感的系统(如金融交易、实时系统)
调优复杂度 中等,可通过 -XX:MaxGCPauseMillis 等参数调优 较低,多数情况下开箱即用,参数较少
Full GC 类型 可能退化为 Serial Old(单线程,长时间 STW) 可能退化为 Serial GC,但概率较低

总结建议:

  • 选择 G1:如果您的应用堆大小在几十GB以内,对停顿时间有一定要求但不是极端敏感,且希望有较好的吞吐量与稳定性,G1 是成熟且广泛使用的选择。

  • 选择 ZGC:如果您的应用堆非常大(上百GB 或 TB 级),且对 GC 停顿时间要求极高(如必须控制在 10ms 以内),ZGC 是更优的选择,尤其适合实时系统、高并发后台服务等场景。

随着 JDK 的发展,ZGC 正在成为未来低延迟 GC 的主流方向,而 G1 依然是当前许多生产系统的可靠选择。

六、堆内存申请后,还会归还给系统吗

程序运行时,会从最小配额-Xms 一直申请到最大配额-Xmx,超出后会OOM。假设当前占用8G,经过垃圾回收后,清理了2G垃圾,此时占用内存是6G,但申请内存还是8G,不会轻易的归还给操作系统

posted on 2018-12-07 19:08  wzyy  阅读(302)  评论(0)    收藏  举报