JVM核心笔记

张开发
2026/4/17 6:21:06 15 分钟阅读

分享文章

JVM核心笔记
一、JVM 运行时内存结构JVM 运行时数据区主要包括Heap堆Method Area方法区Java Stack虚拟机栈Native Method Stack本地方法栈Program Counter Register程序计数器1. Heap堆作用存放对象存放数组例如User user new User(); int[] arr new int[10];这些对象和数组都在堆中。堆的结构Heap ├─ Young Generation新生代 │ ├─ Eden │ ├─ Survivor0 │ └─ Survivor1 └─ Old Generation老年代对象生命周期new 对象 ↓ Eden ↓ Minor GC ↓ Survivor ↓ 年龄增长 ↓ Old2. Method Area方法区作用存储类信息运行时常量池静态变量JIT 编译后的代码JDK 版本区别JDK 7PermGen永久代JDK 8Metaspace元空间JDK8 以后特点元空间使用的是本地内存不再使用 PermGen3. Java Stack虚拟机栈特点线程私有每个线程都有一个独立的栈栈中存什么局部变量方法调用信息操作数栈返回地址等方法调用对应栈帧main() test() add()栈中的压栈顺序add test main每调用一个方法就会创建一个栈帧Stack Frame。4. Program Counter Register程序计数器作用记录当前线程执行到哪一条字节码指令可以理解为当前线程的“执行位置指针”特点线程私有是一块很小的内存区域5. Native Method Stack本地方法栈作用为 JVM 调用本地方法Native 方法服务例如native void test();二、类加载机制1. 类加载器的作用类加载器ClassLoader负责把.class文件加载到 JVM 中。2. 类加载过程类从加载到可用一般经历加载验证准备解析初始化3. 双亲委派模型类加载器层次Bootstrap ClassLoader ↑ Extension ClassLoader ↑ Application ClassLoader加载规则先让父加载器加载父加载器无法加载时子加载器才自己加载优点保证安全避免重复加载经典问题为什么 String 不能被替换因为String由Bootstrap ClassLoader加载应用层无法随意替换核心类。三、对象创建过程Java 中创建对象User user new User();JVM 内部大致过程类加载检查分配内存初始化零值设置对象头执行构造方法对象内存结构对象通常由三部分组成对象头实例数据对齐填充四、垃圾回收GC1. GC 的作用GC 用来回收不再使用的对象释放内存。2. 判断对象是否死亡的方法1引用计数法对象每被引用一次计数加 1引用失效计数减 1。缺点无法解决循环引用问题2可达性分析JVM 实际使用的是可达性分析算法。从GC Roots出发看对象是否可达。常见 GC Roots栈中的引用静态变量引用的对象常量引用的对象JNI 引用的对象如果对象到 GC Roots不可达就可以被回收。五、GC 算法常见 4 种算法标记-清除复制算法标记-整理分代收集1. 标记-清除流程标记垃圾对象清除垃圾对象优点实现简单缺点会产生内存碎片2. 复制算法把存活对象复制到另一块区域。新生代常见结构Eden S0 S1优点没有内存碎片回收效率高缺点需要额外空间3. 标记-整理流程标记移动存活对象清理边界外内存优点没有碎片适用场景老年代4. 分代收集JVM 的核心思想新生代对象存活率低适合复制算法老年代对象存活率高适合标记-整理六、GC 收集器常见收集器SerialParNewCMSG1ZGC1. Serial GC特点单线程Stop The World适用场景客户端、小内存场景2. CMS特点低停顿追求响应时间流程初始标记并发标记重新标记并发清理缺点会产生内存碎片对 CPU 比较敏感3. G1 GC重点特点把堆分成多个Region可预测停顿时间适合较大堆内存场景优势兼顾吞吐量和停顿时间现代生产环境中非常常用4. ZGC特点超低延迟停顿时间非常短适用场景大内存、低延迟系统七、JVM 调优核心参数最重要的四个参数-Xms-Xmx-Xmn-Xss八、-Xms、-Xmx、-Xmn、-Xss详细笔记1.-Xms初始堆内存作用设置 JVM 启动时堆的初始大小。例如-Xms2g表示JVM 启动时初始堆大小为2GB例子java -Xms2g -Xmx4g -jar app.jar表示启动时堆 2GB最大堆 4GB为什么生产环境常把Xms设为和Xmx一样避免堆动态扩容减少扩容带来的停顿提高系统稳定性生产推荐-Xms4g -Xmx4g2.-Xmx最大堆内存作用设置 JVM 堆能使用的最大内存。例如-Xmx8g表示堆最大可使用8GB堆关系Heap Young Old所以Xmx Young Old影响Xmx太小容易频繁 GCXmx太大Full GC 时间可能变长系统总内存压力也更大经验不要把机器内存全部给 JVM一般预留操作系统、本地内存、线程栈、直接内存等空间3.-Xmn年轻代大小作用设置新生代大小。例如-Xmn2g表示年轻代 2GB年轻代结构Young ├─ Eden ├─ S0 └─ S1通常比例为Eden : S0 : S1 8 : 1 : 1例如-Xmn1g大致可理解为Eden ≈ 800MBS0 ≈ 100MBS1 ≈ 100MB影响Xmn太小Minor GC 频繁Xmn太大老年代变小可能更容易 Full GC经验年轻代通常可以是堆的 1/3 左右但是否手动设置Xmn要看使用的 GC注意在G1 GC下通常不建议强依赖-Xmn手工固定年轻代因为 G1 会自行调整分区和代际比例。4.-Xss线程栈大小作用设置每个线程的栈大小。例如-Xss1m表示每个线程栈大小为1MB栈里存什么局部变量方法调用信息操作数栈返回地址例如void test() { int a 10; }变量a一般在栈帧里。影响Xss太小可能出现StackOverflowError常见场景递归层次过深单个线程调用链太深Xss太大会导致每个线程占用更多内存可创建线程数减少所以线程总数 ≈ 可用内存 / 每线程栈大小九、四个参数关系总结参数作用主要影响-Xms初始堆大小启动时堆空间-Xmx最大堆大小JVM 可使用的最大堆内存-Xmn年轻代大小Minor GC 频率、新老年代比例-Xss每线程栈大小线程数量、递归深度十、常见生产配置示例1. 常规服务配置java \ -Xms8g \ -Xmx8g \ -Xss1m \ -XX:UseG1GC \ -XX:MaxGCPauseMillis200 \ -jar app.jar2. 如果使用 Parallel / CMS 等可能会看到java \ -Xms8g \ -Xmx8g \ -Xmn3g \ -Xss1m \ -jar app.jar十一、JVM 问题排查工具常用工具工具作用jps查看 Java 进程jstat查看 GC 情况jmap查看堆内存、导出 dumpjstack查看线程栈MAT分析内存泄漏Arthas在线诊断十二、生产问题排查思路1. Full GC 频繁排查流程jstat 看 GC 频率 ↓ jmap -histo 看大对象 ↓ jmap -dump 导出堆 ↓ MAT 分析是否内存泄漏2. CPU 飙高排查流程top / top -Hp ↓ 找到高 CPU 线程 ↓ jstack 看线程堆栈 ↓ 定位死循环 / 锁竞争 / 频繁计算3. 内存持续上涨排查流程jmap -dump ↓ MAT 分析 ↓ 看是否有对象被长时间引用十三、面试高频答题点1. 为什么-Xms通常要等于-Xmx答避免堆扩容减少扩容带来的停顿提高系统稳定性2.-Xmn影响什么答影响年轻代大小影响 Minor GC 的频率间接影响老年代大小3.-Xss影响什么答影响单个线程栈深度影响系统最多可创建线程数4. Heap 的组成是什么答Heap Young OldYoung 中通常包含Eden Survivor0 Survivor1十四、速记版JVM 四大参数速记-Xms初始堆大小-Xmx最大堆大小-Xmn年轻代大小-Xss每个线程栈大小记忆口诀Xms启动给多少堆Xmx最多能用多少堆Xmn年轻代占多少Xss每个线程栈多大十五、补充纠正点1.-Xmn不是所有 GC 都推荐手动设尤其是G1 GC场景下通常更倾向让 JVM 自己动态调节年轻代而不是强行固定-Xmn。2. GC 日志参数在新版本 JDK 中有变化老写法常见-XX:PrintGCDetailsJDK 9 更推荐-Xlog:gc*

更多文章