容器里堆只用 60% 却被 OOMKilled:JVM 少算的内存去哪了
本文摘要堆只用六成就被杀掉缺口来自元数据、线程栈与直接内存这些非堆项。用NMT把内存拆成八个类别逐项归因再按总账给各类显式设上限。该路径限JDK17容器环境NMT常开多占内存内存贴着限额的服务须谨慎。一、问题与结论kubectl describe pod给出OOMKilledjstat -gc里used约 720MB-Xmx1200m只用到六成Pod 重启后两小时又被杀。差别在口径cgroup 的limits.memory统计的是进程 RSS堆只是子项Metaspace、线程栈、Code Cache 与 Direct Buffer 合计约 800MB 就足以越过 2Gi。排查用-XX:NativeMemoryTracking逐类归因治理是给 Non-Heap 显式设上限并留余量。触发者与业务代码无关堆外分配偏多的服务都会复现常见的是 Netty/gRPC 的零拷贝缓冲区与规模偏大的线程池。二、排查与选择依据两个口径要分清容器侧看docker stats的USAGE与/proc/1/status的VmRSSJVM 侧看GC.heap_info的used差值就是待解释的部分。诊断顺序docker stats --no-stream my-oom-app看总占用与 limitdocker exec my-oom-app cat /proc/1/status | grep VmRSS拿到 RSSdocker exec my-oom-app jcmd 1 VM.native_memory summary拆出八类占用jcmd 1 VM.native_memory baseline建基线隔一段时间用VM.native_memory detail.diff看增量是否回落。判断标准Java Heap的 used 稳定而Internal或Class持续增长且不回落属于 Direct Buffer 泄漏或元数据膨胀Netty 异常路径漏 release、CGLIB 热部署旧类未释放都归此类各类都稳定只是总量偏大属预算不合理改启动参数即可不必动业务代码。替代方案与取舍做法选择条件代价不该用的情况NMT summary 常开定期detail.diff需要逐类归因能改启动参数summary 约增加 5%–10% RSS内存贴着 limit没有余量吃开销显式设MaxMetaspaceSize等上限MaxRAMPercentage60留白只求稳定运行堆利用率偏低上限过紧会抛OutOfMemoryError: Metaspace堆峰值波动大无法预估各类上限JFR 采集jdk.NativeMemoryUsage已有 JDK 11 与分析流程采集与事后分析成本高只想判断是否越限的短命任务K8scontainer_memory_working_set_bytes告警拿不到 JVM 内部指标只能预警不能定位已知根因、要量化修复收益上线不到一周就OOMKilled时先调limits.memory与-Xmx的比例通常更快收敛。三、关键原理NMT 把 JVM native memory 划成八类堆只是第一项NMT 类别内容典型量级Java Heap对象存储-Xmx的 60% 左右ClassMetaspace Compressed Class Space数十到数百 MBThread线程栈线程数 ×-XssCodeJIT Code Cache24–240 MBGC标记位图等 GC 数据结构堆的 5%–20%Internal/Symbol内部结构、符号表数十 MBOtherDirect Buffer、JNI、Unsafe不透明最容易失控三个机制决定预算写法。其一cgroup 记的是 RSS-Xmx并未为其余类别预留空间。其二-XX:UseContainerSupport在 JDK 10 默认开启按容器 limit 修正-XX:MaxRAMPercentage与处理器数量但不会自动收紧 Metaspace、Code Cache 与线程栈。其三-XX:MaxDirectMemorySize默认跟随-XmxDirect Buffer 的回收依赖 Cleaner 与 GC 触发释放时机不受调用方控制。总账按“堆 Metaspace Code Cache 线程数 ×-Xss Direct Buffer GC 开销 NMT 自身开销 ≤limits.memory”来写。四、可运行示例环境为 Docker 与eclipse-temurin:17-jdk镜像cgroup v2 环境同样适用容器内存限额 2GB。先构建镜像再带限额运行最后执行诊断。MemoryEater.java模拟堆内 720MB、Direct Buffer 300MB 与 200 个阻塞线程importjava.nio.ByteBuffer;importjava.util.ArrayList;importjava.util.List;importjava.util.concurrent.CountDownLatch;publicclassMemoryEater{publicstaticvoidmain(String[]args)throwsException{Listbyte[]heapnewArrayList();for(inti0;i720;i){heap.add(newbyte[1024*1024]);// 堆内约 720MB}ListByteBufferdirectnewArrayList();for(inti0;i300;i){direct.add(ByteBuffer.allocateDirect(1024*1024));// 堆外 300MB}CountDownLatchlatchnewCountDownLatch(1);for(inti0;i200;i){// 200 个阻塞线程栈默认 512KB–1MBnewThread(()-{try{latch.await();}catch(InterruptedExceptionignored){}}).start();}System.out.println(ready pidProcessHandle.current().pid());Thread.sleep(Long.MAX_VALUE);}}Dockerfile为各类 Non-Heap 显式设上限并开启 NMTFROM eclipse-temurin:17-jdk WORKDIR /app COPY MemoryEater.java . RUN javac MemoryEater.java # MaxDirectMemorySize 留出余量避免恰好贴 300MB 上限抛 OutOfMemoryError: Direct buffer memory ENTRYPOINT [java,-Xmx1200m,-XX:MaxMetaspaceSize128m,-XX:ReservedCodeCacheSize128m,-XX:MaxDirectMemorySize512m,-XX:NativeMemoryTrackingsummary,-XX:UseContainerSupport,MemoryEater]构建、运行与诊断dockerbuild-toom-diagnosis.dockerrun-d--namemy-oom-app--memory2g oom-diagnosissleep5dockerstats --no-stream my-oom-appdockerexecmy-oom-appcat/proc/1/status|grepVmRSSdockerexecmy-oom-app jcmd1VM.native_memory summarydockerexecmy-oom-app jcmd1GC.heap_infodockerexecmy-oom-appcat/sys/fs/cgroup/memory.max2/dev/null\||dockerexecmy-oom-appcat/sys/fs/cgroup/memory/memory.limit_in_bytes预期输出Java Heapused 约 720MBThread约 200MBInternal/Other约 300MBClassCodeGC约 300MBcommitted 合计约 2GB叠加 NMT 开销后VmRSS贴近 2Gi随后出现OOMKilled。上述数值为未验证示意值。实际输出在终端比对VmRSS与GC.heap_info的 used 差值并确认memory.max为2147483648若差值接近 NMT 各类之和即可确认根因是 Non-Heap 越限。失败处理启动参数里漏掉-XX:NativeMemoryTrackingsummary时jcmd 1 VM.native_memory summary会返回未开启追踪的提示。NMT 只能在 JVM 启动时开启补进ENTRYPOINT后重启 Pod或改用 JFR 事后采样。五、验证结果与边界验证分两步先用示例把容器打到 limit 并拿到OOMKilled事件再逐项设上限重跑观察同一时段detail.diff是否收敛。文中内存分布数字均为未验证示意值。边界四条。NMT 有开销summary 约 5%–10%、detail 约 10%–20% 额外 RSS贴限服务不要长期开 detail。Other里的 Direct Buffer 释放时机不可控-XX:MaxDirectMemorySize只挡越界不保证回收。cgroup v2 需 JDK 15 完整支持JDK 8/11 的 update 版本需单独确认。虚拟线程JDK 21不占平台线程栈Thread一类会明显变小仍要为 pinning 场景预留平台线程预算。参考资料java 命令手册JDK 17jcmd 命令手册JDK 17

相关新闻

RCP 4.5 和 8.5 情景下 1901-2299 年永久冻土融化和碳释放的预测

RCP 4.5 和 8.5 情景下 1901-2299 年永久冻土融化和碳释放的预测

Projections of Permafrost Thaw and Carbon Release for RCP 4.5 and 8.5, 1901-2299简介该数据集包含 1901 年至 2299 年间北半球多年冻土区域的一系列模型预测结果。这些模型预测结果包括一组通用诊断输出的月平均值,空间分辨率为 0.50.5经纬度。这些模型模拟结果…

2026/10/9 9:55:51 阅读更多 →
课程论文堆成山?大学生必备的AI写作效率神器

课程论文堆成山?大学生必备的AI写作效率神器

如果你问大学生最头疼的事情是什么?除了期末周考试,估计就是各种课程论文了。一个学期下来,少则五六篇,多则十几篇——马克思主义基本原理要写论文,大学语文要写论文,专业选修课每门都要交课程论文&#xf…

2026/10/9 9:55:38 阅读更多 →
【大数据毕设项目】

【大数据毕设项目】

文章目录 一、项目开发背景意义 二、项目开发技术 三、项目开发内容 四、项目展示 五、项目相关代码 六、最后 一、项目开发背景意义 生成式AI软件服务快速迭代,用户规模与交互频次激增,算力消耗成为运营成本的核心组成部分。为精准掌握用户行为特…

2026/10/9 9:56:25 阅读更多 →

最新新闻

Claude Code实战:从安装配置到跑通AI编程工作流

Claude Code实战:从安装配置到跑通AI编程工作流

1. Claude Code:这次AI编程工具真的不一样最近有朋友问我:都2025年了,日常写代码到底还有没有必要折腾AI编程工具?说实话,我自己之前也觉得GitHub Copilot这类补全插件已经够用,但真正开始认真使用Claude C…

2026/10/9 10:50:27 阅读更多 →
基于Python+Django的购物商城管理系统毕设源码与数据库实战解析

基于Python+Django的购物商城管理系统毕设源码与数据库实战解析

简介:基于Python的购物商城管理系统毕业设计项目源码与配套数据库,面向计算机相关专业正在做毕设的学生,以及需要项目实战练习的初学者,可支撑课程设计、期末大作业等应用场景。压缩包共384个文件、约15.8MB,其中94个P…

2026/10/9 10:50:27 阅读更多 →
Java个人健康管理APP毕设实战:SSM框架全流程解析

Java个人健康管理APP毕设实战:SSM框架全流程解析

又到了毕业设计集中开题的时间,私信里反复出现同一个问题:“Java的个人健康管理APP这个题目到底难不难?SSM框架现在还让用吗,会不会被导师说技术栈太老?”我的回答向来是:题目本身没问题,问题是…

2026/10/9 10:50:27 阅读更多 →
Unity异步TCP网络通信从原理到落地:连接、粘包、心跳与断线重连全解析

Unity异步TCP网络通信从原理到落地:连接、粘包、心跳与断线重连全解析

有人问我Unity做网络通信怎么入门,我一般会先反问一句:你的业务场景需要实时性强还是可靠性强?答案不同,技术选型完全不同。如果要做实时帧同步,那得研究UDP加自定义可靠性方案;但如果做登录鉴权、道具购买…

2026/10/9 10:50:27 阅读更多 →
Docker部署FunASR语音识别服务:镜像选择、模型挂载与踩坑实录

Docker部署FunASR语音识别服务:镜像选择、模型挂载与踩坑实录

我到现在还记得第一次手工部署FunASR的场景:conda环境建好、依赖装完、模型下好,结果换一台机器全得重来。后来痛定思痛换成Docker部署,整个流程压缩到半小时以内,服务器之间迁移也就两条命令的事。这篇记录我用Docker安装部署Fun…

2026/10/9 10:50:27 阅读更多 →
T3 Stack 全栈开发实战:从脚手架到部署的完整链路与踩坑指南

T3 Stack 全栈开发实战:从脚手架到部署的完整链路与踩坑指南

最近一个月我把一个代号叫 t3code 的项目从零到一完整跑了一遍,这是一个基于 T3 Stack 做的在线代码片段管理应用,支持用户登录、代码片段增删改查、按语言/标签筛选,整体形态就是一个典型的全栈 CRUD 加认证的中小型应用。写这篇文章的起因是…

2026/10/9 10:49:25 阅读更多 →

日新闻

Java时间API实战:LocalDate、Date与ZonedDateTime的转换与避坑指南

Java时间API实战:LocalDate、Date与ZonedDateTime的转换与避坑指南

Java时间API这个话题,隔三差五就会在群里被翻出来讨论一次。上周还有个同事线上处理一个订单超时问题,排查到最后发现是ZonedDateTime序列化后时区丢了,用户在下单当天晚上看到的时间整整差了8个小时。这类问题几乎每个做Java开发的人都遇到过…

2026/10/9 0:00:49 阅读更多 →
EasyTier实践:从NAT穿透到子网代理的异地组网部署与排错

EasyTier实践:从NAT穿透到子网代理的异地组网部署与排错

前几个月我手头有好几台机器需要互相访问:办公室台式机、家里 NAS、还有一台云主机。如果只是偶尔传个文件倒还好,问题是工作场景经常要在几处环境之间来回切换,每次都先登录跳板机再层层代理,实在折腾。我先后试过端口映射、自建…

2026/10/9 0:00:49 阅读更多 →
AI Agent工程实战:从七要素到七个决策点的系统设计指南

AI Agent工程实战:从七要素到七个决策点的系统设计指南

AI Agent 这个词在过去一年里被反复提及,但真正动手搭过一套能跑起来的 Agent 系统的人都知道,从"知道它是什么"到"让它稳定干活"之间隔着一整套工程决策。我前后参与过几个 Agent 项目的落地,从最初用现成框架拼装&…

2026/10/9 0:01:50 阅读更多 →

周新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 15:26:32 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 15:26:40 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/9 10:11:06 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 21:13:17 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 15:26:17 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/9 6:17:20 阅读更多 →