You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java GC线程停顿时间差异原因及停顿时间定义咨询

关于GC线程停顿日志的疑问解答

首先,先明确你日志里两个关键时间的准确定义,这是理解差异的基础:

1. “停顿时间”的准确定义

  • Total time for which application threads were stopped: 这个指标的计时起点是JVM发起“让所有应用线程进入安全点暂停”的请求后,第一个应用线程开始暂停的时刻,终点是最后一个应用线程从安全点恢复运行的时刻。它包含三部分时间:
    • 等待所有应用线程陆续到达安全点的耗时(也就是日志里的Stopping threads took)
    • JVM在安全点内执行核心操作的耗时(比如GC的标记、清理、压缩,或是类卸载、偏向锁撤销等其他安全点操作)
    • 唤醒所有线程的耗时(通常可以忽略不计)
  • Stopping threads took: 这是从JVM发起安全点请求,到最后一个应用线程完全暂停、所有线程都进入安全点的耗时——这段时间里,线程是分批暂停的,不是同时停下。

2. 两次停顿差异巨大的原因

你看到的第一次173ms的停顿,大概率是一次Full GC触发的安全点停顿:
当老年代内存不足、或者需要进行整堆回收时,JVM会触发Full GC,这个过程需要在安全点内完成全局标记、清理、甚至老年代内存压缩等重量级操作,这些操作本身就会消耗大量时间,再加上等待线程进入安全点的时间,总停顿时长自然就长。

而第二次不足1ms的停顿,更可能是一次轻量级的安全点操作,而非GC触发:
JVM除了GC外,还有很多场景会触发安全点停顿,比如:

  • 偏向锁的批量撤销
  • 类元数据的更新或卸载
  • JVM内部的统计信息收集
    这类操作只需要让线程短暂暂停,几乎没有后续的重量级操作,所以总停顿时间几乎等于Stopping threads took的耗时,自然非常短。

3. GC时是否部分线程先挂起,其他线程仍在运行?

没错!JVM触发安全点停顿的时候,所有应用线程并不是同时瞬间暂停的:

  • 处于阻塞状态(比如sleep()、wait()、I/O阻塞)的线程会立刻响应暂停请求,直接进入安全点;
  • 正在执行代码的线程会继续运行,直到到达下一个“安全点”(比如循环迭代的边界、方法返回点、异常抛出点等预设的代码位置)才会暂停。

所以在Stopping threads took的这段时间里,确实是部分线程先挂起,剩下的线程在逐步到达安全点后暂停,直到所有线程都进入安全点,JVM才会开始执行GC的核心操作。

内容的提问来源于stack exchange,提问作者Gang Xie

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 09:29:18