Skip to content

JVM参数基础

1. 这是什么

JVM 参数用于配置内存大小、垃圾回收策略、日志输出、诊断行为和运行特性。
它们是调优的重要入口,但前提始终是先理解问题,再谈参数。

一句话理解:

  • JVM 参数不是“神奇优化开关”
  • 它们只是把 JVM 的资源边界和运行策略显式配出来

2. 为什么重要

参数配置过小会导致:

  • 频繁 GC
  • 内存不足
  • 吞吐下降

参数配置不合理也可能导致:

  • 资源浪费
  • 问题被掩盖
  • 排障信息缺失

学 JVM 参数,核心不是背表,而是知道:

  • 每个参数在解决什么问题

3. 先建立直觉:参数要和目标问题绑定

JVM 参数最常见的几类目标是:

目标常见参数方向
控制堆大小-Xms-Xmx
控制代际 / 区域行为年轻代、老年代、Region 相关参数
选择收集器-XX:+UseG1GC
打开日志与诊断-Xlog:gc*、HeapDump 参数
辅助排障错误日志、堆转储、崩溃信息输出

所以参数不是独立知识点,而是:

  • 现象 -> 目标 -> 参数

这条链路的一部分。

4. 核心内容

4.1 堆大小相关参数

最基础也最常见的是:

  • -Xms:初始堆大小
  • -Xmx:最大堆大小

理解重点:

  • 堆越大,不代表一定越好
  • 太小会导致频繁 GC
  • 太大又可能拉长某些回收阶段、浪费资源

4.2 新生代与老年代相关参数

在不同 JVM 版本和不同收集器下,细节参数会有差异。
学习阶段先抓主线:

  • 这些参数是在控制对象主要活动区域的容量与比例

你不需要一开始就死记所有参数名,更重要的是知道:

  • 年轻代偏短命对象
  • 老年代偏长期存活对象
  • 它们的比例会影响 GC 频率和回收行为

4.3 垃圾收集器选择参数

常见形式例如:

bash
-XX:+UseSerialGC
-XX:+UseParallelGC
-XX:+UseG1GC
-XX:+UseZGC

这类参数回答的是:

  • JVM 采用哪套垃圾收集器实现

4.4 GC 日志参数

现代 JDK 更常见的方式是:

bash
-Xlog:gc*

它的价值非常大,因为:

  • 没有日志,很难知道 JVM 回收行为到底发生了什么
  • 有日志,才能看到停顿、堆变化、收集器行为

4.5 OOM 导出与诊断参数

比较常见的思路是:

  • 出现 OOM 时导出 Heap Dump
  • 保留诊断现场

常见参数例如:

bash
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=...

它们的作用不是防止 OOM,而是:

  • 出事时给你留下证据

5. 学习重点

这一章最重要的是建立这些判断:

  • 参数必须和问题目标绑定
  • 堆大小不是越大越好
  • 先看指标,再调参数
  • 调优是系统工程,JVM 参数只是其中一环
  • 诊断参数和运行参数同样重要

6. 常见问题

6.1 不分析问题,直接复制网上参数模板

这是最常见的误区之一。
别人的业务形态、机器配置、JDK 版本和你的未必一样。

6.2 一次改很多参数,无法判断效果

这样会导致:

  • 调优没有对照组
  • 结论无法归因

6.3 把参数调优当作万能解法

如果根因是:

  • 内存泄漏
  • 对象模型不合理
  • 线程池设计错误

单靠调参数并不能真正解决问题。

7. 动手验证

这一节可以直接操作,重点验证“参数真的生效了”。

7.1 先验证堆大小参数

直接运行:

bash
java -Xms64m -Xmx64m -XshowSettings:vm -version

在当前环境里,我实际看到了这些关键信息:

text
Min. Heap Size: 64.00M
Max. Heap Size: 64.00M

这说明:

  • -Xms-Xmx 已经生效

7.2 再验证收集器选择参数

运行:

bash
java -XX:+UseG1GC -Xlog:gc -version

在当前环境里,我实际看到了:

text
Using G1

这说明:

  • JVM 已按参数切换到 G1 收集器

7.3 再配一个最小可运行示例

新建文件 JvmParamDemo.java,内容如下:

java
public class JvmParamDemo {
    public static void main(String[] args) {
        long maxHeapMb = Runtime.getRuntime().maxMemory() / 1024 / 1024;
        long totalHeapMb = Runtime.getRuntime().totalMemory() / 1024 / 1024;
        System.out.println("maxHeapMb=" + maxHeapMb);
        System.out.println("totalHeapMb=" + totalHeapMb);
    }
}

7.4 编译并运行示例

bash
javac JvmParamDemo.java
java -Xms64m -Xmx64m JvmParamDemo

你通常会观察到类似:

text
maxHeapMb=64
totalHeapMb=64

这说明程序运行时确实感知到了新的堆大小边界。

7.5 如果你想进一步验证 GC 日志

可以执行:

bash
java -Xms32m -Xmx32m -Xlog:gc* JvmParamDemo

虽然这个简单程序未必触发明显 GC,但你可以先确认:

  • GC 日志功能已经成功打开

8. 练习建议

下面这些练习做完,这一章会更扎实:

  • 阅读一套常见启动参数的含义
  • 用小实验验证堆大小变化的效果
  • 为一个示例程序开启 GC 日志并观察输出
  • 总结“参数 -> 目标问题 -> 观察指标”的对应关系

9. 自测问题

  • 为什么 JVM 参数不能脱离场景单独讨论?
  • 哪类参数常和内存容量有关?
  • 为什么调优前先要有指标和现象?
  • 为什么诊断参数和运行参数一样重要?
  • 复制网上参数模板为什么风险很高?

10. 自测核对要点

如果你的回答能覆盖下面这些点,说明这一章基本掌握到位了:

  • JVM 参数是运行策略和资源边界配置,不是万能优化开关
  • -Xms-Xmx 控制堆容量边界
  • 收集器选择参数决定 GC 实现路径
  • GC 日志和 Heap Dump 参数对排障非常关键
  • 参数调优必须绑定现象、指标和验证过程