Java GC 日志出现 humongous allocation 时怎么判断
Java GC 日志里出现 humongous,先不要把它直接判定为内存泄漏。若当前收集器是 G1,判断重点有三层:实际的 Region 大小、对象是否达到半个 Region,以及 Humongous regions: X->Y 是否长期伴随老年代压力、并发标记赶不上分配或 Full GC。只有三组证据能对上,才值得调整分配方式或 G1 参数。
最可靠的第一步是确认 G1 的实际 Region 大小,再用它的一半计算阈值;日志中的 humongous Region 数表示占用的 Region,不等于 Java 对象个数。
官方资料:https://docs.oracle.com/en/java/javase/26/gctuning/garbage-first-g1-garbage-collector1.html
先确认 JVM 的 Region 尺寸
G1 把堆切成大小相同的 Region。对象大小达到单个 Region 的一半,就会走 humongous 分配路径,并占用一段连续的 old-generation Region。这个阈值不是固定的 1 MB 或 2 MB,而取决于本次 JVM 实际选出的 -XX:G1HeapRegionSize。
# 查看本次 JVM 采用的 G1 Region 大小;输出是观测信息,不是调参建议。
java -XX:+PrintFlagsFinal -version 2>&1 | grep G1HeapRegionSize
# 用统一日志保留 GC 标签和堆区变化,便于关联多次事件。
java -XX:+UseG1GC \
-Xlog:gc*,safepoint:file=gc.log:time,uptime,level,tags \
-jar app.jar
例如 Region 是 4 MB,理论判断线就是 2 MB;Region 是 16 MB,判断线就是 8 MB。实际对象还会受到对象头、数组长度和对齐影响,所以不要拿业务字段长度直接和阈值做一一对应。启动日志通常也会打印已选的 Region 大小,排查时应以这次进程的值为准。

Region 大小决定 humongous 的阈值
G1 为一个大对象预留连续 Region,起始 Region 放置对象头部,后续 Region 继续承载对象。最后一个 Region 没被对象填满的部分,在对象整体回收前不能拿给普通对象使用。因此,刚刚超过阈值的大数组可能并不大,却会造成明显的尾部空间浪费。
这也是为什么“堆还有很多空闲空间”与“humongous 分配失败”可以同时出现:前者描述总量,后者还要求找到连续的 Region。一个偶发的大对象不一定有问题;反复创建并长期存活的字节数组、压缩缓冲区、序列化结果或大文本,才更值得继续追踪。
从日志判断是偶发大对象还是持续压力
先让日志包含堆区信息,再看相邻 GC 事件中的变化:
# 只保留与 Region 和堆区判断相关的统一日志标签。
java -Xlog:gc+heap=info,gc=info:file=gc.log:time,uptime,level,tags \
-jar app.jar
# 在副本上快速找出 humongous、老年代和 Full GC 线索;不要把 grep 结果当成对象画像。
grep -E 'Humongous regions|Old regions|Pause Full|Evacuation Failure' gc.log
重点看四个关系:
Humongous regions: X->Y:说明本次 GC 前后有多少 Region 被这类对象占用,不能直接推导出对象数量。Old regions:如果 humongous 占用上升,同时老年代长期抬高,说明大对象正在挤压可回收空间。- 并发标记是否及时完成:大量 humongous 分配可能促使 G1 更早启动并发周期,不能只看单次暂停时长。
Pause Full或Evacuation Failure:这类信号与连续空间不足、回收节奏失配有关,优先级高于一次孤立的 humongous 记录。

先改分配形态,再评估 Region 参数
如果同一业务负载下 humongous Region 持续增加,第一选择通常是减少大对象的创建和存活时间:把一次性聚合结果改成分块处理,复用可控大小的缓冲区,限制缓存中的大值,并确认调用链不会无意中长期持有数组。这样解决的是根因,且不会改变整个堆的布局。
如果对象确实是业务必需品,再在压测环境评估增大 -XX:G1HeapRegionSize。Region 变大后,部分对象可能不再达到半 Region 阈值,但 Region 数量、年轻代布局和暂停行为也会一起变化,不能只凭“humongous 变少”判定成功。扩堆、并发标记线程和 IHOP 也只能针对已经确认的压力模式调整。
复查要使用同一版本、同一堆上限和相近的业务负载,至少对比 humongous Region 峰值与回落、Old Region 趋势、Full GC 次数、最长暂停和分配速率。若只是阈值变化而业务分配速率未变,说明问题可能被隐藏,并未真正消失。
常见判断误区
看到 humongous 就说明内存泄漏吗?
不是。它首先是 G1 对大对象的分类。只有在对象持续存活、Region 不回落并伴随堆压力时,才需要继续做引用链或堆转储分析。
把 G1HeapRegionSize 调大一定更好吗?
不一定。它可能让部分对象回到普通分配路径,也可能改变收集粒度和暂停特征。先证明大对象分配是主要压力,再用相同负载做前后对照。
因此,Java GC 日志出现 humongous allocation 时,正确顺序是“确认收集器和 Region 大小、计算阈值、关联多次日志、最后才做方案调整”。把一个词还原成一组可交叉验证的证据,才能避免把正常的大对象误判成泄漏,也避免用全局参数掩盖分配设计问题。
Go testing.TB Setenv 和 t.Cleanup 如何配合
- 上一篇
- Go testing.TB Setenv 和 t.Cleanup 如何配合
- 下一篇
- Go build tag 表达式中逗号和空格如何解释
-
- 文章 · java教程 | 2小时前 | Java · jdbc · 数据库异常处理 · java jdbc SQLException SQLSTATE vendorCode
- Java SQLException SQLState 和 vendorCode 如何分层
- 229浏览 收藏
-
- 文章 · java教程 | 4小时前 | Java · module-info · requires transitive ·
- Java module requires transitive 如何影响下游编译
- 257浏览 收藏
-
- 文章 · java教程 | 6小时前 | Java · 模块系统 · ServiceLoader · java ServiceLoader JPMS 模块路径
- Java ServiceLoader 在模块路径下为何找不到 provider
- 455浏览 收藏
-
- 文章 · java教程 | 7小时前 | Java · 异常处理 · 异步编程 · java completablefuture whenComplete
- Java CompletableFuture whenComplete 如何记录异常而不改变结果
- 439浏览 收藏
-
- 文章 · java教程 | 8小时前 |
- Java HttpClient BodyHandlers.ofPublisher 如何处理 Publisher 取消
- 385浏览 收藏
-
- 文章 · java教程 | 10小时前 | map · Java · 集合 · java linkedhashmap SequencedMap
- Java SequencedMap 反向遍历如何保持键值关系
- 229浏览 收藏
-
- 文章 · java教程 | 11小时前 |
- Java Stream teeing 收集器适合哪些双结果场景
- 500浏览 收藏
-
- 文章 · java教程 | 12小时前 |
- Java StructuredTaskScope 失败传播和取消顺序如何读
- 400浏览 收藏
-
- 文章 · java教程 | 14小时前 |
- Java virtual thread 访问连接池时并发上限怎么设
- 272浏览 收藏
-
- 文章 · java教程 | 15小时前 | Java · 空值处理 · record pattern · java record pattern
- Java record pattern 解构嵌套 record 时如何处理 null
- 190浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 485次学习
-
- PubMedQA
- 深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
- 42次使用
-
- H2O EvalGPT
- H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
- 136次使用
-
- LMArena
- LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
- 73次使用
-
- HELM
- 深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
- 34次使用
-
- CMMLU
- 深入了解CMMLU中文评估基准,涵盖67个学科主题,提供数据集下载、Zero-shot/Five-shot评估方法及排行榜,助力优化中文语言模型性能。
- 23次使用
-
- Go goroutine 泄漏怎么排查:pprof 快照、止血和回退手册
- 2026-07-09 374浏览
-
- Spring Boot 开虚拟线程后吞吐没上去?先查这 5 个生产坑
- 2026-06-02 239浏览
-
- JFR 排查 Spring Boot 慢接口:别急着加缓存,先抓一段 Flight Recording
- 2026-06-02 126浏览
-
- CompletableFuture 异步接口卡死复盘:别让 commonPool 背锅到凌晨
- 2026-06-02 191浏览
-
- MyBatis N+1 查询实战:列表接口 1 秒变 8 秒,别只怪数据库
- 2026-06-02 116浏览

