jvm 知识汇总
JVM 管理
堆内存 (Heap Memory)
-
是什么:它是 JVM 运行时管理的一块最大的内存区域,是所有线程共享的。
-
做什么:几乎所有通过
new关键字创建的对象和数组都在这里分配内存。你可以把它想象成一个巨大的“对象公寓楼”,所有新创建的对象都住在这里。垃圾回收器(GC)的主要工作场所就是这片区域。
👶 年轻代 (Young Generation)
-
是什么:堆内存的一部分,通常占堆总大小的 1/3。
-
做什么:这是对象的“出生地”和“托儿所”。绝大多数新创建的对象都会首先被分配到年轻代。它的特点是对象数量多,但生命周期普遍很短,很多对象“朝生夕死”。
- 内部结构:年轻代内部又细分为一个 Eden 区和两个 Survivor 区。大部分对象在 Eden 区诞生,经过筛选后,存活的会进入 Survivor 区。
👴 老年代 (Old Generation)
- 是什么:堆内存的另一部分,通常占堆总大小的 2/3。
- 做什么:这里存放的是“长寿命”的对象。当一个对象在年轻代里经历了几次“考核”(GC)后依然存活,就会被晋升到老年代,相当于从“托儿所”毕业,进入了“养老院”。一些体积特别大的对象也可能直接分配到老年代。
🧹 Young GC (YGC / Minor GC)
-
是什么:专门针对年轻代的垃圾回收行为。
-
触发时机:当年轻代的 Eden 区空间不足时,就会触发一次 Young GC。
- 过程与特点:
- 它会快速扫描年轻代,将那些不再被引用的“短命”对象清理掉。
- 幸存下来的对象年龄会+1,并被移动到另一个 Survivor 区。
- 如果对象的年龄达到了预设的阈值(默认是15),它就会从年轻代晋升到老年代。
- Young GC 发生非常频繁,但因为只清理年轻代,且大多数对象都是垃圾,所以速度很快,停顿时间也相对较短。
🚨 Full GC (FGC / Major GC)
- 是什么:对整个堆内存(包括年轻代、老年代以及元空间等)进行的一次全面、彻底的垃圾回收。
- 触发时机:通常在以下几种情况发生:
- 老年代空间不足,无法容纳从年轻代晋升上来的对象。
- 显式调用了
System.gc()方法(但不保证一定会执行)。 - 元空间(Metaspace)空间不足。
- 过程与特点:
- Full GC 是一次“大扫除”,它会整理整个堆的内存,因此耗时非常长,会导致应用程序出现明显的卡顿(Stop-The-World)。
- 在性能调优中,我们的核心目标之一就是尽量避免或减少 Full GC 的发生频率。
垃圾回收器(Garbage Collector, GC)
常用垃圾回收器
每个版本的 jdk 对应的垃圾回收器是不同的,回收策略方式也不同,适配不同场景
CMS 回收器
-XX:+UseConcMarkSweepGC
gc 日志如下

2026-04-22T18:29:11.992+0800: 634.333: [GC (Allocation Failure) 634.333: [ParNew: 1855206K->150153K(1887488K), 0.1371639 secs] 3921700K->2256434K(6081792K), 0.1373426 secs] [Times: user=0. 49 sys=0.01, real=0.14 secs] 2026-04-22T18:29:12.130+0800: 634.471: [GC (CMS Initial Mark) [1 CMS-initial-mark: 2106281K(4194304K)] 2260231K(6081792K), 0.0390175 secs] [Times: user=0.13 sys=0.01, real=0.04 secs] 2026-04-22T18:29:12.170+0800: 634.511: [CMS-concurrent-mark-start] 2026-04-22T18:29:12.481+0800: 634.822: [CMS-concurrent-mark: 0.311/0.311 secs] [Times: user=0.61 sys=0.02, real=0.31 secs] 2026-04-22T18:29:12.481+0800: 634.822: [CMS-concurrent-preclean-start] 2026-04-22T18:29:12.829+0800: 635.170: [CMS-concurrent-preclean: 0.347/0.348 secs] [Times: user=0.64 sys=0.06, real=0.35 secs] 2026-04-22T18:29:12.829+0800: 635.170: [CMS-concurrent-abortable-preclean-start] 2026-04-22T18:29:16.758+0800: 639.099: [GC (Allocation Failure) 639.099: [ParNew: 1827977K->209664K(1887488K), 0.1274023 secs] 3934258K->2316166K(6081792K), 0.1275787 secs] [Times: user=0.49 sys=0.00, real=0.13 secs] CMS: abort preclean due to time 2026-04-22T18:29:20.086+0800: 642.427: [CMS-concurrent-abortable-preclean: 6.932/7.257 secs] [Times: user=27.16 sys=1.21, real=7.25 secs] 2026-04-22T18:29:20.086+0800: 642.427: [GC (CMS Final Remark) [YG occupancy: 1104159 K (1887488 K)]642.427: [Rescan (parallel) , 0.2847491 secs]642.712: [weak refs processing, 0.0026899 secs]642.715: [class unloading, 0.0479635 secs]642.763: [scrub symbol table, 0.0227686 secs]642.786: [scrub string table, 0.0017714 secs][1 CMS-remark: 2106502K(4194304K)] 3210661K(6081792K), 0.3676621 secs] [Times: user=1.21 sys=0.00, real=0.37 secs] 2026-04-22T18:29:20.455+0800: 642.796: [CMS-concurrent-sweep-start] 2026-04-22T18:29:22.722+0800: 645.063: [GC (Allocation Failure) 645.063: [ParNew: 1887488K->160588K(1887488K), 0.2092911 secs] 3498855K->1879131K(6081792K), 0.2094598 secs] [Times: user=0.76 sys=0.00, real=0.21 secs] 2026-04-22T18:29:27.316+0800: 649.657: [GC (Allocation Failure) 649.657: [ParNew: 1838412K->108201K(1887488K), 0.0765652 secs] 3228881K->1498670K(6081792K), 0.0767189 secs] [Times: user=0.30 sys=0.00, real=0.08 secs] 2026-04-22T18:29:32.321+0800: 654.662: [GC (Allocation Failure) 654.662: [ParNew: 1786025K->146810K(1887488K), 0.0888121 secs] 2609420K->970205K(6081792K), 0.0889518 secs] [Times: user=0.35 sys=0.01, real=0.09 secs] 2026-04-22T18:29:38.005+0800: 660.346: [GC (Allocation Failure) 660.346: [ParNew: 1824634K->209664K(1887488K), 0.1503263 secs] 2493190K->914569K(6081792K), 0.1504979 secs] [Times: user=0.56 sys=0.01, real=0.15 secs] 2026-04-22T18:29:38.563+0800: 660.904: [CMS-concurrent-sweep: 17.054/18.107 secs] [Times: user=66.64 sys=2.87, real=18.11 secs] 2026-04-22T18:29:38.563+0800: 660.904: [CMS-concurrent-reset-start] 2026-04-22T18:29:38.671+0800: 661.012: [CMS-concurrent-reset: 0.108/0.108 secs] [Times: user=0.26 sys=0.13, real=0.11 secs] 2026-04-22T18:29:41.671+0800: 664.012: [GC (Allocation Failure) 664.012: [ParNew: 1887488K->172335K(1887488K), 0.1576992 secs] 2527824K->875967K(6081792K), 0.1578523 secs] [Times: user=0.59 sys=0.00, real=0.16 secs]
View Code
触发条件:
老年代使用率过高,空间不足
过程:
1、CMS-concurrent-mark(并发标记):后台与业务线程并行完成,初步标记
2、CMS-concurrent-preclean+CMS-concurrent-abortable-preclean(并发预清理):它继续做和预清理一样的工作(扫描脏卡、处理新生代引用),为了减轻下一个阶段——也就是那个会暂停用户的 “重新标记 (Remark)” 阶段的压力
3、CMS Final Remark(最终标记):触发会触发 STW (Stop-The-World),暂停所有应用线程,以确保在这一瞬间对象引用关系不再变化。然后,GC 会快速修正那些在并发期间发 生变动的对象的标记记录,保证最终结果的准确性。
4、清理(CMS-concurrent-sweep):真正执行清理垃圾操作
5、重置(CMS-concurrent-reset):结束清理,重置数据和状态为下次做准备
总结:
设计原则是最小化 STW,提前标记,牺牲部分 CPU 开销(后台线程提前标记扫描,与业务线程并行)
在容器环境配置了 limit后,由于 cpu限制 CFS 机制会导致 cpu使用上安装毫秒分时分片容易导致标记线程抢不到 cpu资源,而标记过程一般需要持续 2-3 秒,不允许中断,否则回收失败,最终触发 Full GC,长时间 STW 进而导致业务线程被挂起无响应
G1(Garbage-First)
自 JDK 9 起成为 HotSpot 虚拟机的默认选择。它的设计目标是在大内存、多核处理器的环境下,实现高吞吐量与可预测的低延迟之间的最佳平衡。
-XX:+UseG1GC
G1 的核心创新在于其独特的内存布局和回收策略,旨在克服传统分代收集器的局限性。
Region 化的内存布局
G1 摒弃了新生代和老年代在物理上完全隔离的布局,而是将整个 Java 堆划分为多个大小相等的独立区域(Region),每个 Region 的大小在 1MB 到 32MB 之间。
逻辑分代:虽然物理上是独立的 Region,但 G1 仍然保留了分代的概念。每个 Region 在不同时刻可以扮演不同的角色:Eden、Survivor、Old 或 Humongous(专门存放超过 Region 大小 50% 的大对象)。
.
工作流程与关键阶段
G1 的垃圾回收主要分为两种模式:Young GC 和 Mixed GC。
Young GC (年轻代回收)
当 Eden 区的 Region 被耗尽时触发。它是一个完全的 STW(Stop-The-World)操作,采用复制算法,将 Eden 和 Survivor 区中的存活对象复制到新的 Survivor Region 或直接晋升到老年代。
Mixed GC (混合回收,这是 G1 的核心)
当老年代的占用率达到特定阈值(由 -XX:InitiatingHeapOccupancyPercent 控制,默认为 45%)时,会触发一个并发的标记周期,随后执行一系列的 Mixed GC。
Mixed GC 不仅回收所有的年轻代 Region,还会额外选择一部分老年代 Region 进行回收。
这个并发标记周期包含以下几个关键阶段:
初始标记 (Initial Mark):STW 阶段。标记从 GC Roots 直接可达的对象。此阶段通常会与一次 Young GC 同步进行,以复用其停顿时间。
并发标记 (Concurrent Mark):与应用线程并发执行。遍历整个对象图,找出所有存活的对象。此阶段使用 SATB (Snapshot-At-The-Beginning) 算法来保证标记的准确性。
最终标记 (Final Mark / Remark):STW 阶段。处理在并发标记期间因应用运行而产生的少量引用变动,完成最终的标记工作。
筛选回收 (Live Data Counting & Evacuation):STW 阶段。根据预设的停顿时间目标,选择一批“价值”最高的老年代 Region,将其中的存活对象复制到其他空闲 Region 中,然后清空 这些被回收的 Region。
Full GC
当 Mixed GC也无法回收内存到理想水位就会触发 Full GC
总结
优势
平衡性能:在吞吐量和延迟之间取得了很好的平衡,既不像 Parallel GC 那样停顿时间长,也不像 CMS 那样牺牲吞吐量。
无内存碎片:通过在回收过程中复制和整理存活对象,G1 能有效避免内存碎片问题,这对于长期运行的应用至关重要。
适合大堆:Region 化的设计使其能够高效地管理非常大的堆内存(如 6GB 以上)。
可预测的停顿时间模型这是 G1 的一大亮点。它允许用户通过参数 -XX:MaxGCPauseMillis 明确指定期望的 GC 最大停顿时间(默认为 200ms)
相比于 CMS 它的标记过程在容器环境不受 CMS 策略影响,被中断后可以继续,不会被终止,更适合容器环境
劣势
小堆场景不占优:在小堆内存(如小于 4GB)的场景下,其复杂的内部管理开销可能导致性能不如更简单的 Parallel GC。
JVM 启动参数
-Dfile.encoding=UTF-8
#高版本支持,容器里面自动识别 limit,根据 limit总量的 90% 作为堆内存是使用率,当然如果手动指定了 -Xms -Xmx 它俩优先级就更高了
-XX:+UseContainerSupport
-XX:MaxRAMPercentage=90.0
#设置年轻代和老年代比例为 1:2,-Xmn优先级高于它
-XX:NewRatio=2
#实时写 gc日志,打印详情,设置 gc日志路径
-XX:+PrintGCDetails
-XX:+PrintGCDateStamps
-verbose:gc
-Xloggc:/debug/gc.log
#发生oom时候退出之前导出堆内存快照,方便时候排查内存泄露原因
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/debug/
#设置堆内存大小和元数据区大小 -Xms6g -Xmx8g -Xmn3g
-XX:MetaspaceSize=512M
-XX:MaxMetaspaceSize=512M
#配置GC回收器类型,以及GC时候STW时间
-XX:+UseConcMarkSweepGC
-XX:MaxGCPauseMillis=200
-XX:ConcGCThreads=1


浙公网安备 33010602011771号