揭开 Java 容器“消失的内存”之谜:云监控 2.0 SysOM 诊断实践

简介: JVM 没满,Pod 却挂了?可能是 C2 Compiler 在“偷偷吃内存”。阿里云云监控 2.0 的 SysOM 系统诊断帮你穿透 JNI 黑盒,找出真正的内存元凶!

作者:肖杰韬(六滔)


背景


在前一篇文章《一次内存诊断,让资源利用率提升 40%:揭秘隐式内存治理[1]中,我们系统性地剖析了云原生环境中隐性内存开销的诊断方法,通过 SysOM 系统诊断实现了对节点/Pod 级由文件缓存、共享内存等系统级内存资源异常消耗的精准定位。


然而,部分场景下内存异常仍可能源于应用进程本身的内存申请,但是对于应用内存泄漏问题,尽管是应用的开发者,也需要投入大量的精力去利用对应语言的内存分析工具去找出根因;以 Java 应用为例,当传统线下 IDC 集群中的 Java 应用完成云原生架构转型后,伴随容器化封装与资源配额管控的实施,用户普遍反馈 Java 应用 Pod 出现持续性内存超限及 Kubernetes OOMKilled 事件。这一系列现象主要集中在三个关键矛盾点


1. 容器内存监控与 JVM 堆内存的显著差异:Pod 内存占用常超出 JVM 堆内存(含堆外内存)数倍,形成“消失的内存”谜团。

2. 容器化改造后的 OS 兼容性问题:同一业务系统在切换 OS 或容器化后,出现内存占用模式突变。

3. 工具链覆盖盲区:传统 Java 内存分析工具无法覆盖 JNI 内存、LIBC 内存等非 JVM 内存区域。


为此,云监控 2.0[2]中的 SysOM 系统诊断对应用内存进一步深挖,结合应用和操作系统的角度实现对主机、容器运行时及具体的 Java 应用进程进行内存占用拆解,快速有效地识别出 Java 内存占用的元凶。


Java 内存全景分析


为了找出消失的内存,我们首先要了解 Java 进程的主要内存组成以及现有工具和监控主要覆盖的部分;如下图所示可分为:


JVM 内存

  • 堆内存可通过 -Xms/-Xmx 参数控制,内存大小可通过 memorymxbean 等获取。
  • 堆外内存包括元空间、压缩类空间、代码缓冲区、直接缓冲、线程栈等内存组成;它们分别可以通过 -XX:MaxMetaspaceSize(元空间)、-XX:CompressedClassSpaceSize(压缩类空间)、-XX:ReservedCodeCacheSize(代码缓冲区)、-XX:MaxDirectMemorySize (直接缓冲)、-Xss(线程栈)参数限制。

非 JVM 内存

  • JNI 本地内存:即通过本地方法接口调用 C、C++ 代码(原生库),并在这部分代码中调用 C 库(malloc)或系统调用(brk、mmap)直接分配的内存。

1765267553473_971ad37c30a04098b11bed01641aacd7.png


Java 常见“内存泄露”


JNI 内存泄漏

经过上一章中对 Java 内内存全景的分析,其实已经可以揭开第一个容易造成内存黑洞的隐藏 Boss-JNI 内存,因为这部分内存暂时没有工具可以获取其占用大小。


通常来说,编写相关业务代码的同学会认为代码中没有使用本地方法直接调用 C 库,所以不会存在这些问题,但是代码中引用的各种包却有可能会使用到 JNI 内存,比如说经典的使用 ZLIB 压缩库不当导致的 JNI 泄漏问题[3]


LIBC 内存管理特性

JVM 向 OS 申请内存的中间,还存在着一层中间层 -C 库,JVM 调用 malloc、free 申请/释放内存的过程中其实还要经过这一个二道贩子;以 gibc 中默认的内存分配器 ptmalloc 为例 glibc 的 ptmalloc 内存分配器存在以下特征:


  • Arena 机制每个线程维护 64M Arena,多线程场景下易产生内存碎片
  • Top Chunk 管理内存空洞导致无法及时归还 OS
  • Bins 缓存策略JVM 释放的内存暂存于 bins 中,造成统计偏差 [4-5]

1765267593202_12789fa51e734c93bf89e93e1ef3a3d5.png

Linux 透明大页(THP)影响

在 OS 层,Linux 中的透明大页(Transparent Huge Page)机制也是造成 JVM 内存和实际内存差异的一大元凶。简单来说,THP 机制就是 OS 会将 4kb 页变成 2M 的大页,从而减少 TLB miss 和缺页中断,提升应用性能,但是也带来了一些内存浪费。如应用申请了一段 2M 的虚拟内存,但实际只用了里面的 4kb,但是由于 THP 机制,OS 已经分配了一个 2M 的页了[6]

SysOM Java 内存诊断实践


下面将以汽车行业客户在从线下 idc 集群迁移至云上 ACK 集群时遇到的由于 JNI 内存泄漏导致 Pod 频繁 OOM 为例,介绍如何通过云监控 2.0 的 SysOM 系统诊断来一步步找出 Java 内存占用的元凶。


诊断使用限制:

  • 目前仅支持 openJDK 1.8 以上版本
  • 使用 JNI 内存 Profiling 功能需要至操作系统控制台先对实例进行纳管[3]有一定的资源和性能开销(内存占用根据符号大小最高达 300MB)


C2 compiler JIT 内存膨胀案例

案例背景

某汽车客户在 ACK 集群迁移过程中,多个 Java 服务 Pod 出现偶发性 OOM。特征表现为:

  • Pod 内存接近限制时触发 OOM
  • JVM 监控显示内存正常
  • 无明显请求异常或流量波动

排查过程

  • 尝试在内存高水位时对 Pod 发起内存全景分析。

1765267636077_e2bfe1c7df4f401aa68fd929002b5708.png

  • 我们可以了解到当 Pod 中容器内存使用已经接近 limit,从诊断结论和容器内存占用分析中,我们可以看到容器内存主要是由于 Java 进程内存占用导致。

1765267648533_77899ff019f04b2a90e046aeebb39113.png

对 Java 进程发起内存分析,查看诊断报告。报告展示了 Java 进程所在 Pod 和容器的 rss 和 WorkingSet(工作集)内存信息、进程 Pid、JVM 内存使用量(即 JVM 视角的内存使用量)、Java 进程内存使用量(进程实际占用内存),进程匿名用量以及进程文件内存用量。

1765267661773_9ff3af995f81488bb6726e1e9a761195.png

通过诊断结论和 Java 内存占用饼图我们可以发现,进程实际内存占用比 JVM 监控显示的内存占用大 570M,全都由 JNI 内存所贡献[4]

1765267671890_c5b0d64d564b4c3f9ce6f8ea7125bd12.png

开启 JNI(Java Native Interface)内存分配 profiling,报告列出当前 Java 进程 JNI 内存分配调用火焰图,火焰图中为所有分配 JNI 内存的调用路径。(说明:由于是采样采集,火焰图中的内存大小不代表实际分配大小)。

1765267686524_28bebe0506fe441bbf37b0f9d32644eb.png

  • 从内存分配火焰图中,我们可以看到主要的内存申请为 C2 compiler 正在进行代码 JIT 预热;
  • 但是由于诊断的过程中没有发现 pod 有内存突增;所以我们进一步借助可以常态化运行的 Java CPU 热点追踪功能[5]尝试抓取内存升高时的进程热点,并通过热点对比[6]尝试对内存正常时的热点进行对比。

  • 通过热点栈和热点分析对比,发现内存突增时间点的 cpu 栈也是 c2 compiler 的 JIT 栈,且 c2 compiler 热点前有部分业务流量突增,且业务代码使用了大量反射操作(反射操作会导致 c2 compiler 进行新的预热)。

结论和解决方案

C2 compiler JIT 过程申请 JNI 内存,且由于 glibc 内存空洞等原因导致申请内存放大且延时释放。

1. 调整 C2 compiler 参数,让其编译策略更保守,可以尝试调整相关参数,观察内存消耗变化。

2. 调整 glibc 环境变量 MALLOC_TRIM_THRESHOLD_,让 glibc 及时将内存释放回操作系统。


总结


通过系统化的内存诊断方法,我们得以穿透 JVM 黑盒,揭示 JNI、LIBC 及 OS 层面的内存管理特性。阿里云操作系统控制台的内存全景分析功能,为容器化 Java 应用提供了从进程级到系统级的立体化诊断能力,帮助开发者精准定位内存异常根源,有效避免 OOM 事件的发生。


相关链接:

[1]《一次内存诊断,让资源利用率提升 40%:揭秘隐式内存治理

[2] 云监控-ECS 洞察-SysOM 系统诊断

https://cmsnext.console.aliyun.com/next/region/cn-shanghai/workspace/default-cms-1808078950770264-cn-shanghai/app/host/host-sysom

[3] 操作系统控制台实例纳管

https://help.aliyun.com/zh/alinux/user-guide/system-management?spm=a2c4g.11186623.help-menu-2632541.d_2_0_4.14ef243dMTjYF1&scm=20140722.H_2851198._.OR_help-T_cn~zh-V_1#7895eb3dedfty

[4] 操作系统控制台 Java 内存诊断

https://help.aliyun.com/zh/alinux/user-guide/java-memory-diagnostics?spm=a2c4g.11186623.help-menu-2632541.d_2_0_1_0_0_2.2fd8243d1slu08&scm=20140722.H_2979954._.OR_help-T_cn~zh-V_1

[5] 操作系统控制台热点追踪

https://help.aliyun.com/zh/alinux/user-guide/process-hotspot-tracking

[6] 操作系统控制台热点对比分析

https://help.aliyun.com/zh/alinux/user-guide/hot-spot-comparative-analysis

相关文章
|
4月前
|
移动开发 小程序 前端开发
小程序开发平台有哪些?哪个好
小程序项目落地的第一步,也是最关键的一步,就是开发平台的精准选型。它不仅影响项目的开发周期与成本投入,更直接决定了后续业务的适配度和运营上限。企业需结合自身技术能力、预算区间、功能需求等核心要素综合权衡。本文将对主流小程序开发平台进行分类拆解,通过详细对比和场景化推荐,帮助不同类型的企业找到最契合的解决方案。
551 9
|
开发者
MacM1安装MAT全流程安装指南
MAT作为开发者分析堆栈快照信息的常用工具,本文介绍了在MBP M1中安装指南。
3574 1
MacM1安装MAT全流程安装指南
|
安全 微服务
(七)、Eureka自我保护
(七)、Eureka自我保护
(七)、Eureka自我保护
|
3月前
|
SQL 人工智能 Java
告别传统 Text-to-SQL:基于 Spring AI Alibaba 的数据分析智能体 DataAgent 深度解析
DataAgent是基于Spring AI Alibaba生态构建的企业级AI数据分析师,融合NL2SQL、多智能体协作与RAG技术,支持多数据源分析、自动纠错与可视化报告生成,让业务人员零代码获取深度数据洞察。
2518 42
告别传统 Text-to-SQL:基于 Spring AI Alibaba 的数据分析智能体 DataAgent 深度解析
|
4月前
|
人工智能 算法 安全
王耀恒:GEO技术培训是“授人以渔”而不是“授人以鱼”
在AI技术飞速迭代的今天,GEO培训讲师王耀恒坚持“授人以渔”,通过培养认知、构建与进化三重自主性,赋能学员掌握应对变革的元能力。他拒绝快餐式技巧传授,倡导深入原理、自主设计与持续进化,捍卫人在技术洪流中的主体性与创造力,重塑技术教育的人文价值。(239字)
|
4月前
|
JavaScript 前端开发 Java
2026版基于springboot的在线招聘管理系统
本文探讨了基于Web的在线招聘平台在当前社会经济环境下的发展背景、意义及研究现状。随着互联网技术进步,在线招聘平台通过大数据、人工智能等技术实现求职者与岗位的精准匹配,提升招聘效率与用户体验。国内外研究分别聚焦于功能优化、数据安全、国际化及新技术应用。系统采用SpringBoot、Java、Vue.js与MySQL等技术实现高效、稳定的招聘服务,推动人力资源管理数字化发展。
|
4月前
|
存储 人工智能 自然语言处理
LlamaIndex 深度实战:用《长安的荔枝》学会构建智能问答系统
本文深入浅出地讲解了RAG(检索增强生成)原理与LlamaIndex实战,通过《长安的荔枝》案例,从AI如何“读书”讲起,详解三大关键参数(chunk_size、top_k、overlap)对问答效果的影响,并结合真实实验展示不同配置下的回答质量差异。内容兼顾新手引导与进阶优化,帮助读者快速构建高效的文档问答系统。
814 22
LlamaIndex 深度实战:用《长安的荔枝》学会构建智能问答系统
|
4月前
|
存储 安全 数据安全/隐私保护
Joplin:一款真正属于你的开源笔记与待办事项应用
Joplin是一款免费开源的笔记工具,支持Markdown、多端同步与端到端加密,保障数据自主权。支持全平台使用,可同步至云存储,真正实现隐私安全与知识自由管理,是信息时代的理想笔记伴侣。(239字)
1282 13
|
4月前
|
自然语言处理 运维 Serverless
打破 IK 分词“架构陷阱”——阿里云 ES Serverless 索引级词典的完美热更新实践
本文将通过一个真实事故的复盘,解析开源 IK 分词器架构设计中的不足,并介绍阿里云 ES Serverless 如何通过“索引级词典”能力,彻底解决热更新引发的搜索错配问题。
455 9
|
Java Spring 容器
深入理解@EnableAspectJAutoProxy的力量
深入理解@EnableAspectJAutoProxy的力量
1360 0

热门文章

最新文章