-
我给容器里的 Java 应用明明设了 2GB 的内存上限、也没配多大的堆,可它一加压就被 OOMKilled 反复重启,我对着监控看 JVM 堆用量百思不得其解,最后才搞懂这个老版本 JVM 根本不知道自己被关在了 2GB 的容器里它按宿主机那 64GB 内存算了个十几 GB 的最大堆的深度复盘
我把 Java 服务部署到 K8s、给容器设了 limits.memory: 2Gi,想着 2GB 够它跑、启动 JVM 也没特意配 -Xmx。低负载正常,可流量一上来负载一加压 Pod 就被 OOMKilled、重启、再被杀陷入 CrashLoop。我以为是堆不够或内存泄漏,可监控里 JVM 堆使用量还没涨多高就被杀;又怀疑 limit 设小了,可这服务物理机上撑死用一两 GB。直到进容器执行 …- 4
- 0
-
我的服务通过域名调用下游,下游因为故障切换换了 IP,我的服务却还死死连着那个已经下线的旧 IP 一直报连接失败,重启之后才恢复,原来是 DNS 解析结果被缓存了很久不刷新的深度复盘
我的服务通过域名 api.downstream.com 调下游。某天下游故障切换、运维把域名指向了新的健康节点(DNS 里的 IP 变了)。按理说我用的是域名、IP 变了该自动跟上,可现实是我的服务一直在连那个已下线的旧 IP、疯狂报 Connection refused,别的服务都正常,直到我重启才恢复。复盘才搞懂:用域名访问要先经过 DNS 解析把域名翻译成 IP,而这个解析结果会被缓存(系统…- 0
- 0
-
我的 Java 服务在容器里跑着跑着就被干掉重启,kubectl 显示 OOMKilled,可服务器明明有几十 G 内存,排查发现是 JVM 根本不知道自己被关在了一个小盒子里的深度复盘
我的 Java 服务跑在 K8s 里、给容器设了 memory limit 512Mi,可它跑着跑着就被杀掉重启,kubectl describe pod 写着 OOMKilled,而宿主机明明有几十 G 内存,JVM 自己也没抛 OutOfMemoryError。查到底才明白:JVM 没感知到容器的内存限制——它启动时按看到的机器总内存(宿主机几十 G,不是容器 cgroup 限制的 512Mi…- 0
- 0
-
一个 JVM 服务因为默认永久缓存了 DNS 解析结果,在下游域名切换 IP 后还死连着早已下线的旧地址,连接全失败:一次 DNS 缓存的深度复盘
下游第三方做机房迁移,把域名解析到新 IP、旧 IP 下线,域名没变我们本该无感,结果服务大面积连接失败,而服务器上 nslookup 查的是新 IP、重启服务就好了。根因是 JVM 有独立于 OS 的 DNS 缓存,networkaddress.cache.ttl 默认可能是 -1(永久缓存)——进程首次把域名解析成旧 IP 后就永久记住、再也不重新解析,下游换 IP 后还死连旧地址、不重启不自…- 2
- 0
-
我给容器设了 2G 内存上限,Java 服务却反复被 OOMKilled 重启,JVM 日志里还说自己堆远没满,我对着容器里的 JVM 不感知 cgroup 内存限制按宿主机内存设堆这个坑排查了大半天的复盘
一个让我对容器里的程序到底看到多少内存彻底搞明白的 DevOps 坑,抓狂在一个矛盾现象:容器被系统以内存超限 OOMKilled 杀掉,可 JVM 自己的监控却一脸无辜说堆还远没满,一边喊内存爆了一边说还多着呢。Java 服务部署 K8s 容器设内存上限 2Gi,Pod 反复重启 Reason=OOMKilled、Exit137、Restart Count 飙升;进容器看 JVM 说堆用得好好的…- 0
- 0
-
我的 Java 容器上线后总是莫名其妙被杀、日志没有任何异常就直接退出 137,我对着 OOMKilled 和容器内存限制排查了大半天的复盘
把一个跑得好好的 Java 服务容器化扔上 K8s 后,它时不时无声无息地重启:应用日志干干净净、没有任何异常堆栈,进程就直接没了。直到 kubectl describe pod 看到 Last State: OOMKilled, Exit Code: 137,我才意识到不是程序崩了,是它被外面强杀了。排查大半天才搞懂根因:容器用 cgroup 把内存限制在 1G,但老版本 JVM 不感知容器、通…- 2
- 0
-
我的服务用域名连下游,对方机器扩缩容换了 IP 之后,我的服务却死活还在连那台早已下线的旧机器、疯狂报连接失败,我排查了大半天才发现是 DNS 被永久缓存了的复盘
我的服务用域名连下游,下游扩缩容换了 IP、更新了 DNS 记录,我的服务却死活还连那台早已下线的旧 IP、疯狂报 connection refused/超时;可 dig 查那个域名明明早就是新 IP 了,而且重启我的服务就好、下次换 IP 又犯。深挖才懂是 DNS 缓存:我的 JVM 把启动时解析到的旧 IP 永久缓存了——networkaddress.cache.ttl 在装了 Securit…- 2
- 0
-
我的 Java 服务一上 K8s 就莫名其妙地被反复重启、退出码永远是 137,我对着 OOMKilled 这个状态和容器内存限制排查了大半天才搞懂的惨痛经历
我的 Java 服务在虚拟机上稳如老狗,一上 K8s 就反复重启,kubectl describe 显示 Reason: OOMKilled、Exit Code: 137。我给容器配了 4G limit、虚拟机上 4G 也够用,怎么会内存不足?深挖才懂:JVM 在容器里"看不见"cgroup 的内存 limit——容器 limit 是 4G 但节点宿主机有 64G,我没设 -X…- 0
- 0
-
容器明明限制了 1G 内存,Java 服务却一上线就被 OOMKilled 反复重启:我在 Docker 里栽进 JVM 看不见容器内存限制的那次排查复盘
一个平时只用几百兆的 Java 服务,部署到限制 1Gi 内存的容器里,却一启动就 OOMKilled、陷入 CrashLoopBackOff。钻进容器一看,JVM 认为自己的最大堆是 8G——它读到的是宿主机 32G 物理内存、按 1/4 算出 8G,完全看不见 cgroup 给的 1G 限制。这篇从容器=隔离+限制的本质讲到 UseContainerSupport/MaxRAMPercenta…- 0
- 0
-
容器设了 2GB 内存上限服务却反复被 OOMKilled、可 JVM 堆明明没满:JVM 不感知容器限制按宿主机算堆撑爆容器的避坑复盘
这是我们把一个老 Java 服务上容器时踩的第一个也是最懵的一个坑。我们把这个服务打成镜像部署到 K8s 给它的容器设了一个内存上限 2GB,我们估摸着这个服务平时也就用几百兆内存 2GB 绰绰有余了。可服务一启动跑不了多久就被 K8s 给 OOMKilled 因内存超限被杀了,杀了之后自动重启重启完跑一会又被杀如此反复陷入了 CrashLoopBackOff 崩溃重启循环根本起不来。我特别纳闷这…- 6
- 0
-
宿主机内存够却被 OOMKilled:容器 JVM 内存避坑
我们把一个 Java 服务容器化上了 K8s,给 Pod 配了 2GB 内存上限,本以为足够宽裕。可上线后容器三天两头重启,Pod 状态写得明明白白:OOMKilled、退出码 137。最费解的是这台宿主机有 64GB 内存空闲得很,进容器用 top、free 看显示的全是宿主机那 64GB 富得流油,可容器就是一次次以内存超限为由被处决。排查好一阵真相才浮出水面、经典得让人哭笑不得:我那个版本的…- 0
- 0
-
下游换了 IP 我却死连旧址:JVM DNS 缓存避坑
下游团队做了一次寻常的机房迁移:换了台机器、域名没变,只把 DNS 指向新 IP,并通知调用方切换无感知。可切换之后我们的服务开始疯狂报错,连接超时、连接被拒,日志全是连不上下游的红字。诡异的是同一台机器上我用 ping 和 curl 访问那个域名,解析到的明明是新 IP、访问也完全正常,可我的 Java 进程就是死活连着那个早已废弃的旧 IP 不撒手;把进程重启一下问题立刻消失。这个重启就好的特…- 2
- 0
-
从粗放 JVM 运维 CMS 大促高峰 Full GC 十几秒 STW 把交易服务冻死大面积超时 + 默认参数裸跑从不按负载调堆和分代 + 静态 Map 缓存无上限只进不出缓慢漏到 OOM 周期性崩溃重启 + 性能问题靠几个人围一起凭印象猜哪段慢挑可疑处改改上线试盲人摸象白忙几天 + 热点路径循环里反复 new 加字符串 + 拼接加装箱海量临时对象涌入新生代 Young GC 频繁晋升加重 Full GC + 线程池核心数最大数队列长全靠拍脑袋甚至用 Executors 无界队列任务积压到 OOM + 共享数据无脑 synchronized 锁整个方法粒度极粗高并发大批线程挤一把锁排队吞吐被锁死 + 堆外 DirectByteBuffer 泄漏堆内监控一切正常进程却被容器 OOM Killer 反复杀查大半天没头绪 + 不懂 JIT 新实例冷启动全解释执行刚接流量就大量超时误判成网络问题 + 线上 JVM 黑盒平时不看出事才 SSH 上去 jmap 导几十G大堆把垂危服务彻底压垮 → 2026 现代 JVM 性能工程 G1/ZGC 低延迟回收设停顿目标 + 按负载调堆 Xms=Xmx 分代 + HeapDumpOnOutOfMemoryError 加 MAT 引用链定位泄漏加 Caffeine 缓存上限 + JFR 加 async-profiler 火焰图数据驱动定位热点 + StringBuilder 加预分配容量加避免装箱加逃逸分析减分配 + ThreadPoolExecutor 精细化有界队列加拒绝策略加命名 + ConcurrentHashMap 加 LongAdder 替代重锁 + NMT 原生内存追踪加 MaxDirectMemorySize 治堆外 + 分层编译加预热 warm-up 解决冷启动 + JFR 持续黑匣子加 Micrometer 加 Prometheus/Grafana 可观测 87 天战役复盘:47 套工程修法 + 7 个 P0 复盘 + 6 条工程哲学
9 人的 Java 平台与性能工程团队 87 天把一套跑了六年、日交易量从每天几百万笔涨到几亿笔后 JVM 性能问题集中爆雷的核心交易系统——大促高峰期老问题 CMS 因老年代碎片触发 Full GC 一停就是十几秒 STW 把整个交易服务冻死导致大面积超时、JVM 参数基本是默认裸跑从来没有按照服务的负载特征去认真调过堆大小和分代比例、一个静态 Map 当缓存用却没设任何上限只进不出运行十几天就…- 2
- 0
-
从 Java 11 + Spring Boot 2.7 + Hystrix + Eureka + MyBatis + Maven → Java 21 LTS + Spring Boot 3.4 + Virtual Threads + GraalVM AOT + Resilience4j + Nacos + JdbcClient + Gradle 8.11 全栈升级 67 天踩坑录:15 反模式 + 18 修法
29 位 Java 工程师 67 天把公司"交易撮合 / 清结算 / 风控 / 用户中心 / 网关 / 消息推送"6 条核心服务,从 Java 11 + Spring Boot 2.7 + Spring Cloud Hoxton + Tomcat + MyBatis + JUnit 4 + Maven 重构到 Java 21 LTS + 22 preview + Spring …- 5
- 0
-
从 Java 17 → 21 LTS + Spring Boot 3.4 + GraalVM Native + Virtual Threads 全栈现代化 23 天踩坑录:9 反模式 + 11 修法
47 工程师 23 天把 32 个 Java service 从 17 + Spring Boot 3.2 升级到 21 LTS + Spring Boot 3.4 + GraalVM Native + Virtual Threads + ZGC Generational,踩了 9 个反模式 + 5 次回滚 + 1 次 P0 + 2 次 P1,沉淀 11 套修法 + 25 个引申话题 + 10 条…- 8
- 0
-
Java 服务每周 OOM Metaspace 续命 22 个月的复盘:CGLIB ClassLoader 锁死 + 5 种修法
一个 Spring Boot 服务每周都要 rolling restart 一次救命,运维忘了发起 cron 直接 OOMKilled。挖了 5 天,发现是某 SDK 用 CGLIB 每次反射都新建匿名 ClassLoader,Metaspace 类只增不减。本文是完整复盘:jstat/jcmd/MAT 工具链 + 三层引用链 + 5 种修法 + 8 条字节码使用纪律。- 11
- 0
-
K8s Pod 频繁 OOMKilled 但应用日志看起来一切正常的 9 天复盘:JVM 堆只是冰山一角 + 6 层因果链 + 10 条治理纪律
接手新组发现 Pod 每天被 OOMKilled,前任团队加了 4 次内存(4Gi→16Gi)都没解决。9 天复盘找出真凶:JVM 堆只是冰山一角,真正吃内存的是 Direct Memory、Metaspace、JNI、RocksDB mmap 等"看不见"的部分。本文 6 层因果链、NMT+jemalloc+pmap 三件套、4 种修法、10 条治理纪律。- 0
- 0
-
Java ThreadLocal 不 remove 引发的数据串号事故复盘:5 小时定位 + 5 种修法 + 8 条上下文纪律
Tomcat 线程池下 ThreadLocal 不 remove 导致用户上下文被复用,VIP 客户看到了别人的订单和手机号,P0 事故 5 小时停服、9 个客户数据合规事件。这篇完整复盘事故时间线、ThreadLocal 真实内存语义(value 强引用 + 线程池复用)、heap dump 分析、5 种修法(手动 remove / Scope try-with-resources / TTL …- 0
- 0
-
JVM 内存调优完全指南:从一次"OOM 就加 -Xmx 越调越卡"看懂为什么堆大小不是越大越好
2023 年我维护一个 Java 数据处理服务上线一年都跑得稳稳的某次业务量翻倍后开始频繁 OOM 我的第一反应跟很多人一样加内存把 -Xmx 从 4G 调到 8G 再调到 16G 我心里很笃定堆越大能装的对象越多 OOM 自然就解决了可等我真把内存加上去一串麻烦冒了出来第一种最先把我打懵内存加大之后服务确实不 OOM 了可接口延迟从 100 毫秒涨到了 800 毫秒 GC 日志里满是 Full …- 0
- 0
-
JVM 内存与 GC 完全指南:从一次半夜 OOM 告警看懂堆内存怎么排查
2023 年的一个凌晨两点,我被告警电话叫醒:一个核心 Java 服务被系统 OOM Killer 杀掉了。重启、又挂、再重启,堆内存像一条笔直的斜线一路往上爬,涨到顶就崩。我第一反应是"流量涨了内存不够",准备提工单扩容——幸好在提单之前先把堆 dump 下来看了一眼:堆里 80% 的空间被一个 static HashMap 占着,塞了几百万个对象,一个都没被清理。这根本不是…- 7
- 0
-
进程半夜无声消失:一次 Linux OOM Killer 排查复盘
一个 Java 订单服务在凌晨 3 点突然消失被守护脚本拉起,应用日志干净地停在一条正常业务日志后再无任何异常堆栈,像被一枪打死连哼都没哼。排查梳理:进程消失分自己崩和被他杀两类,被杀的证据不在应用日志里要去看内核日志;OOM Killer 用 SIGKILL 杀进程这个信号无法被捕获,所以进程没机会打任何遗言,日志干净到毫无征兆恰恰是被偷袭的特征;dmesg -T 看 killed proces…- 0
- 0
-
线上内存慢慢涨到 OOM:一次 ThreadLocal 内存泄漏的复盘
Web 服务运行三五天后内存只涨不落,最终 OOM,靠定时重启续命。堆 dump 显示对象被线程池线程通过 ThreadLocal 死死拽住。几天彻底搞清:ThreadLocal 存值原理、ThreadLocalMap 弱引用设计、线程池复用导致的泄漏与数据串号、finally remove 铁律与 TTL 跨线程传递。- 3
- 0
-
Full GC 后堆只降了 21M:一次 JVM 内存泄漏排查的复盘
服务每隔三四天就有实例变慢、CPU 冲高、重启即愈,典型的频繁 Full GC。GC 日志里 Full GC 后堆只降 21M,基本锁定内存泄漏。dump 堆用 MAT 一查,根子是一个 static HashMap 缓存只进不出。几天排查 JVM 内存:泄漏与容量之分、GC 日志、MAT 分析、缓存治理、ThreadLocal、内存监控。- 2
- 0
-
Full GC 频繁:接口每隔几分钟卡顿一次的排查复盘
查询服务接口 P99 周期性尖刺,每隔三五分钟卡顿两三秒。查慢 SQL、网络都不是,打开 GC 日志才看清是频繁 Full GC。几天治理:读懂 GC 日志、jstat/jmap 定位、dump 出一个 static 无界本地缓存占堆 76%、缓存加上限、换 G1、排查其他诱因、补齐 GC 监控。- 0
- 0
JVM
幸运之星正在降临...
点击领取今天的签到奖励!
恭喜!您今天获得了{{mission.data.mission.credit}}积分
我的优惠劵
-
¥优惠劵使用时效:无法使用使用时效:
之前
使用时效:永久有效优惠劵ID:×
没有优惠劵可用!
























