高 进阶
JVM常用调优参数#
一句话答案#
核心参数:-Xms/-Xmx(堆大小)、-XX:+UseG1GC(收集器)、-XX:MaxGCPauseMillis(目标停顿)、-XX:+HeapDumpOnOOM。
核心要点
线程共享(所有线程共同访问):
- 堆(Heap):对象实例存放在这里,多线程都可以访问 → 需要同步控制
- 方法区(Metaspace):类信息、常量池、静态变量 → 需要同步控制
线程私有(每个线程独立拥有):
- 虚拟机栈:每个线程有自己的栈,栈帧随方法调用入栈/出栈
- 本地方法栈:同上,服务 native 方法
- 程序计数器:记录线程自己的执行位置,线程切换时恢复
这是多线程内存可见性问题的根源:
- 线程 A 修改了堆上的共享对象,线程 B 不一定立即可见(CPU 缓存与主存不一致)
- Java 内存模型(JMM)通过
volatile、synchronized、happens-before规则来保证可见性
面试回答(2分钟版)
JVM 调优参数我按内存、GC、诊断三个维度来说。内存方面,-Xms 和 -Xmx 设置堆的初始和最大值,建议设成一样避免运行时堆动态伸缩带来的性能开销;-XX:MetaspaceSize 和 MaxMetaspaceSize 控制元空间大小,动态代理或大量类加载的应用需要适当调大。GC 方面,-XX:+UseG1GC 选择 G1 收集器,配合 -XX:MaxGCPauseMillis 设置目标停顿时间,G1 会自动调整 Region 回收策略来尽量满足目标。诊断方面,-XX:+HeapDumpOnOutOfMemoryError 是必配参数,OOM 时自动导出堆快照保留现场;-Xloggc 开启 GC 日志用于事后分析。理解这些参数背后的原理很重要:堆是线程共享区域存放对象实例,栈和程序计数器是线程私有的天然安全,多线程可见性问题的根源就在于线程工作内存和主内存的不一致,需要 volatile 和 synchronized 来保证。实际调优要结合业务场景和压测数据,不能照搬网上配置。
追问与易错
追问方向:
- “-Xms 和 -Xmx 为什么建议设成一样?”→ 避免 JVM 运行时动态伸缩堆大小带来的性能开销和 GC 停顿,预分配固定内存减少内存申请和释放的系统调用
- “怎么选择 GC 收集器?”→ 吞吐优先选 Parallel GC,低延迟选 G1(堆 > 4GB)或 ZGC(超大堆),JDK8 默认 Parallel,JDK9+ 默认 G1;小堆 + 单核可用 Serial
- “你在生产环境设过哪些 JVM 参数?”→ 经验题,常见组合:-Xms/-Xmx 设相同值、-XX:+UseG1GC、-XX:MaxGCPauseMillis=200、-XX:+HeapDumpOnOutOfMemoryError、-Xloggc 开启 GC 日志、-XX:MetaspaceSize 调大防频繁 Full GC
易错点:
- ❌ 照搬网上参数不结合实际场景
- ❌ 忘记设 HeapDumpOnOOM