JVM 笔记
JVM 学习笔记:从整体结构与堆内存划分讲起,再深入 G1 收集器的暂停时间目标、Region 划分与常用 GC 日志参数。
记录碰到到 JVM 问题
- 设置了
-Xms128m -Xmx128m,应用为什么还是要占用 300 MB 左右的内存 - G1 GC
JVM 学习笔记:从整体结构与堆内存划分讲起,再深入 G1 收集器的暂停时间目标、Region 划分与常用 GC 日志参数。
记录碰到到 JVM 问题
-Xms128m -Xmx128m,应用为什么还是要占用 300 MB 左右的内存从一次「-Xms128m -Xmx128m 为何仍占 300MB」的疑问出发,梳理 JVM 的核心组件与非堆内存的构成。
有一天被负责 BI 的同事问道,为什么应用设置了 -Xms128m -Xmx128m 后,应用还是要占用 300 mb 左右的内存大小 想当然回答到:因为还有其他东西占用,这个只是用来约束栈堆的。 但是事后想了下,回答得不够好,就有以下这个文章重新梳理下这个答案
核心组件包括:

其中 -Xms128m -Xmx128m用来控制 堆 的起始和最大的限制。由于还有其他组件也需要运行,所以总体大小应该是超过 128 mb 的。
在非堆中有:
G1 为什么被设计出来:可预测的停顿时间与软目标、Region 划分与历史预测模型,以及常用的 GC 日志与诊断参数。
为什么使用 G1 , 在JDK8之后的版本中,G1 将会成为默认的 GC , 那么了解和使用 G1 是个不错的学习方向。在当前时间点:2025年5月20日时,JDK 版本已经来到了以下这个阶段
那么在后续的版本中还有 ZGC / Shenandoah / Epsilon GC , 其中 CMS 在 JDK9 中弃用,在 14 中移除
G1 的主要解决两个关键点:
之前的 GC : CMS / Parallel GC 在执行 标记-清扫 / 标记-复制 时,需要一次性扫描大量的对象,导致 STW 的时长不可控,波动大。
G1 的处理方案是:
好处:每次 GC 暂停时只处理有限的 Region , 能够较准确估算清理大约需要的耗时,从而让暂停时间可预测。也更容易达到 用户在启动参数中通过 -XX:MaxGCPauseMillis= 指定的最大暂停时间目标
G1 会“预演”——根据历史数据预测这次 GC 的停顿耗时,并据此调整本次 GC 的工作量,使得每次停顿都尽可能接近我们想要的那个值。
尽最大努力去满足,但在内存压力,对象分配速率极高或堆碎片严重时,也可能超出目标
因此,G1 对暂停时间的管控是一种“努力达成但不绝对保证”的方式——这就是“软目标(Soft-Goal)”的含义
Region 区域大小是在 JVM 启动时计算和定义的。它基于尽可能接近 2048 个区域的原则,每个区域的大小为 2 的幂,介于 1 到 64 MB 之间。更简单地说,对于一个 12 GB 的堆:

也可以选择通过 -XX 显式指定区域大小。设置区域大小时,务必了解堆大小比将创建的区域数量,因为区域数量越少,G1 的灵活性就越低,扫描、标记和收集每个区域所需的时间也就越长。在所有情况下,空区域都会被添加到一个无序链表中,也称为“空闲列表”。
The flags are: 这些标志是:
| -Xloggc:/path/to/gc.log -Xloggc:/路径/到/gc.log | Path where the GC logs are written GC 日志写入的路径 |
|---|---|
| -XX:+UseGCLogFileRotation | Enable GC log file rotation 启用 GC 日志文件轮换 |
| -XX= |
Number of rotated GC logs files to retain 要保留的轮换 GC 日志文件数量 |
| -XX= |
Size of each GC logs file to initiate rotation 启动轮换的每个 GC 日志文件的大小 |
| -XX:+PrintGCDetails | Detailed GC log 详细的 GC 日志 |
| -XX:+PrintGCDateStamps -XX:+打印 GCDateStamps | Actual date and timestamp of the collection 收集的实际日期和时间戳 |
| -XX:+PrintGCApplicationStoppedTime | Amount of time the application stopped during GC 应用程序在 GC 期间停止的时间量 |
| -XX:+PrintGCApplicationConcurrentTime | Amount of time the application ran between GCs 应用程序在 GC 之间运行的时间量 |
| -XX:-PrintCommandLineFlags | Prints all the command line flags in the GC log 在 GC 日志中打印所有命令行标志 |
The flags are: 这些标志是:
| -XX:+PrintAdaptiveSizePolicy | Details about the collector ergonomics 关于收集器人体工程学的详细信息 |
|---|---|
| -XX:+PrintTenuringDistribution | Survivor space usage and distribution Survivor 空间使用及分配 |
| -XX:+PrintReferenceGC -XX:+打印参考 GC | Time spent processing references 处理参考文献所花的时间 |
最后,我们还有诊断和实验标志。这些标志可以添加大量日志记录,应仅在必要时以及尝试调试特定问题时使用。
| -XX:+UnlockDiagnosticVMOptions -XX:+解锁诊断虚拟机选项 | |
|---|---|
| -XX:+G1SummarizeConcMark | Summarizes Concurrent Mark at JVM exit 总结 JVM 退出时的并发标记 |
| -XX:+G1PrintHeapRegions | Print the heap regions selected for allocation, cleanup, reuse, compact, cset, commit, failure, etc… 打印选择用于分配、清理、重用、压缩、cset、提交、失败等的堆区域… |
| -XX:+G1PrintRegionLivenessInfo | Prints previous and next liveness data per Old region before and after every concurrent mark cycle 在每个并发标记周期之前和之后打印每个旧区域的上一个和下一个活跃度数据 |
| -XX:+G1SummarizeRSetStats -XX=1 | Print RSet processing information every X, where X is measured in GC cycles 每 X 次打印 RSet 处理信息,其中 X 以 GC 周期为单位 |
| -XX:+PrintSafepointStatistics -XX=1 -XX:+打印安全点统计信息 -XX=1-XX:+LogVMOutput-XX=/path/to/gc.log -XX:LogFile = /路径/到/gc.log | Prints the reason and some details about safepoint synchronization. Can control how many events to collect before printing. By default, logs to STDOut - LogVMOutput can push it to a file 打印原因以及有关安全点同步的一些详细信息。可以控制打印前收集的事件数量。默认情况下,日志记录到 STDOut - LogVMOutput 可以将其推送到文件 |
| -XX:+UnlockExperimentalVMOptions -XX:+解锁实验虚拟机选项 | |
| -XX=fine, finer, finest -XX=fine,更精细,最精细 | Increases logging verbosity on collections 增加集合的日志详细程度 |
| -XX:+G1TraceEagerReclaimHumongousObjects | Prints details about live and dead Humongous objects during each collection 打印每次收集期间存活和死亡的 Humongous 对象的详细信息 |
| -XX:+G1ConcRegionFreeingVerbose | Debug JVM 调试 JVM |
最后,我们还有诊断和实验标志。这些标志可以添加大量日志记录,应仅在必要时以及尝试调试特定问题时使用。
| -XX:+UnlockDiagnosticVMOptions -XX:+解锁诊断虚拟机选项 | |
|---|---|
| -XX:+G1SummarizeConcMark | Summarizes Concurrent Mark at JVM exit 总结 JVM 退出时的并发标记 |
| -XX:+G1PrintHeapRegions | Print the heap regions selected for allocation, cleanup, reuse, compact, cset, commit, failure, etc… 打印选择用于分配、清理、重用、压缩、cset、提交、失败等的堆区域… |
| -XX:+G1PrintRegionLivenessInfo | Prints previous and next liveness data per Old region before and after every concurrent mark cycle 在每个并发标记周期之前和之后打印每个旧区域的上一个和下一个活跃度数据 |
| -XX:+G1SummarizeRSetStats -XX=1 | Print RSet processing information every X, where X is measured in GC cycles 每 X 次打印 RSet 处理信息,其中 X 以 GC 周期为单位 |
| -XX:+PrintSafepointStatistics -XX=1 -XX:+打印安全点统计信息 -XX=1-XX:+LogVMOutput-XX=/path/to/gc.log -XX:LogFile = /路径/到/gc.log | Prints the reason and some details about safepoint synchronization. Can control how many events to collect before printing. By default, logs to STDOut - LogVMOutput can push it to a file 打印原因以及有关安全点同步的一些详细信息。可以控制打印前收集的事件数量。默认情况下,日志记录到 STDOut - LogVMOutput 可以将其推送到文件 |
| -XX:+UnlockExperimentalVMOptions -XX:+解锁实验虚拟机选项 | |
| -XX=fine, finer, finest -XX=fine,更精细,最精细 | Increases logging verbosity on collections 增加集合的日志详细程度 |
| -XX:+G1TraceEagerReclaimHumongousObjects | Prints details about live and dead Humongous objects during each collection 打印每次收集期间存活和死亡的 Humongous 对象的详细信息 |
| -XX:+G1ConcRegionFreeingVerbose | Debug JVM 调试 JVM |