0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

如何使用NMT和pmap来解决JVM的资源泄漏问题

openEuler 来源:openEuler 作者:宋尧飞 2021-09-24 16:00 次阅读

编者按:笔者使用 JDK 自带的内存跟踪工具 NMT 和 Linux 自带的 pmap 解决了一个非常典型的资源泄漏问题。这个资源泄漏是由于 Java 程序员不正确地使用 Java API 导致的,使用 Files.list 打开的文件描述符必须关闭。本案例一方面介绍了怎么使用 NMT 解决 JVM 资源泄漏问题,如果读者遇到类似问题,可以尝试用 NMT 来解决;另一方面也提醒 Java 开发人员使用 Java API 时需要必须弄清楚 API 使用规范,希望大家通过这个案例有所收获。

背景知识:

NMT

NMT 是 Native Memory Tracking 的缩写,一个 JDK 自带的小工具,用来跟踪 JVM 本地内存分配情况(本地内存指的是 non-heap,例如 JVM 在运行时需要分配一些辅助数据结构用于自身的运行)。

NMT 功能默认关闭,可以在 Java 程序启动参数中加入以下参数来开启:

-XX:NativeMemoryTracking=[summary | detail]

其中,“summary” 和 “detail” 的差别主要在输出信息的详细程度。

3cb43d90-10ac-11ec-8fb8-12bb97331649.png

开启 NMT 功能后,就可以使用 JDK 提供的 jcmd 命令来读取 NMT 采集的数据了,具体命令如下:

jcmd 《pid》 VM.native_memory [summary | detail | baseline | summary.diff | detail.diff | shutdown]

NMT 参数的含义可以通过 “jcmd 《pid》 help VM.native_memory” 命令查询。通过 NMT 工具,我们可以快速区分内存泄露是否源自 JVM 分配。

pmap

对于非 JVM 分配的内存,经常需要用到 pmap 这个工具了,这是一个 linux 系统自带工具,能够从系统层面输出目标进程内存使用的详细情况,用法非常简单:

pmap [参数] 《pid》

常用的选项是 “-x” 或 “-X”,都是用来控制输出信息的详细程度。

上图是 pmap 部分输出信息,每列含义为

pYYBAGFNe46AXEijAACM5oGR0ow649.png

现象:

某业务集群中,多个节点出现业务进程内存消耗缓慢增长现象,以其中一个节点为例:

3cd60e48-10ac-11ec-8fb8-12bb97331649.png

如图所示,这个业务进程当前占用了 4.7G 的虚拟内存空间,以及 2.2G 的物理内存。已知正常状态下该业务进程的物理内存占用量不超过 1G。

分析:

使用命令 “jcmdVM.native_memory detail” 可以看到所有受 JVM 监控的内存分布情况:

3cfaa4e2-10ac-11ec-8fb8-12bb97331649.png

上图只是截取了 nmt(Native Memory Tracking) 命令展示的概览信息,这个业务进程占用的 2.2G 物理内存中,受 JVM 监控的大概只占了 0.7G(上图中的 committed),意味着有 1.5G 物理内存不受 JVM 管控。JVM 可以监控到 Java 堆、元空间、CodeCache、直接内存等区域,但无法监控到那些由 JVM 之外的 Native Code 申请的内存,例如典型的场景:第三方 so 库中调用 malloc 函数申请一块内存的行为无法被 JVM 感知到。

nmt 除了会展示概览之外,还会详细罗列每一片受 JVM 监控的内存,包括其地址,将这些 JVM 监控到的内存布局和用 pmap 得到的完整的进程内存布局做一个对比筛查,这里忽略 nmt 和 pmap(下图 pmap 命令中 25600 是进程号)详细内存地址的信息,直接给出最可疑的那块内存:

3d0e578a-10ac-11ec-8fb8-12bb97331649.png

由图可知,这片 1.7G 左右的内存区域属于系统层面的堆区。

备注:这片系统堆区之所以稍大于上面计算得到的差值,原因大概是 nmt 中显示的 committed 内存并不对应真正占用的物理内存(linux 使用 Lazy 策略管理进程内存),实际通常会稍小。

系统堆区主要就是由 libc 库接口 malloc 申请的内存组合而成,所以接下来就是去跟踪业务进程中的每次 malloc 调用,可以借助 GDB:

3d235a5e-10ac-11ec-8fb8-12bb97331649.png

实际上会有大量的干扰项,这些干扰项一方面来自 JVM 内部,比如:

3d3cc782-10ac-11ec-8fb8-12bb97331649.png

这部分干扰项很容易被排除,凡是调用栈中存在 “os::malloc” 这个栈帧的干扰项就可以直接忽视,因为这些 malloc 行为都会被 nmt 监控到,而上面已经排除了受 JVM 监控内存泄漏的可能。

另一部分干扰项则来自 JDK,比如:

3d6b9ee0-10ac-11ec-8fb8-12bb97331649.png

有如上图所示,不少 JDK 的本地方法中直接或间接调用了 malloc,这部分 malloc 行为通常是不受 JVM 监控的,所以需要根据具体情况逐个排查,还是以上图为例,排查过程如下:

3dac2b22-10ac-11ec-8fb8-12bb97331649.png

注意图中临时中断的值(0x0000ffff5fc55d00)来自于第一个中断 b malloc 中断发生后的结果。

这里稍微解释一下上面 GDB 在做的排查过程,就是检查 malloc 返回的内存地址后续是否有通过 free 释放(通过 tb free if X3 这个命令,具体用法可以参考 GDB 调试),显然在这个例子中是有释放的。

通过这种排查方式,几经筛选,最终找到了一个可疑的 malloc 场景:

3dbaf18e-10ac-11ec-8fb8-12bb97331649.png

从调用栈信息可以知道,这是一个 JDK 中的本地方法 sun.nio.fs.UnixNativeDispatcher.opendir0,作用是打开一个目录,但后续始终没有进行关闭操作。进一步分析可知,该可疑 opendir 操作会周期性执行,而且都是操作同一个目录 “/xxx/nginx/etc/nginx/conf”,看来,是有个业务线程在定时访问 nginx 的配置目录,每次访问完却没有关闭打开的目录。

分析到这里,其实这个问题已经差不多水落石出。和业务方确认,存在一个定时器线程在周期性读取 nginx 的配置文件,代码大概是这样子的:

3dfba080-10ac-11ec-8fb8-12bb97331649.png

翻了一下相关 JDK 源码,Files.list 方法是有在末尾注册一个关闭钩子的:

3e0bb2b8-10ac-11ec-8fb8-12bb97331649.png

也就是说,Files.list 方法返回的目录资源是需要手动释放的,否则就会发生资源泄漏。

由于这个目录资源底层是会关联一个 fd 的,所以泄漏问题还可以通过另一个地方进行佐证:

3e3fafaa-10ac-11ec-8fb8-12bb97331649.png

该业务进程目前已经消耗了 51116 个 fd!

假设这些 fd 都是 opendir 关联的,每个 opendir 消耗 32K,则总共消耗 1.6G,显然可以跟上面泄漏的内存值基本对上。

总结:

稍微了解了一下,发现几乎没人知道 JDK 方法 Files.list 是需要关闭的,这个案例算是给大家都提了个醒。

编辑:jq

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • Linux
    +关注

    关注

    87

    文章

    11296

    浏览量

    209358
  • 源码
    +关注

    关注

    8

    文章

    639

    浏览量

    29185
  • JVM
    JVM
    +关注

    关注

    0

    文章

    158

    浏览量

    12220
  • JDK
    JDK
    +关注

    关注

    0

    文章

    81

    浏览量

    16592

原文标题:使用 NMT 和 pmap 解决 JVM 资源泄漏问题

文章出处:【微信号:openEulercommunity,微信公众号:openEuler】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    如何利用气体压力传感器监测气体泄漏

    在化工、石油、天然气等行业中,气体泄漏可能导致严重的安全事故和环境污染。因此,及时准确地监测气体泄漏对于保障人员安全和环境保护至关重要。气体压力传感器作为一种有效的监测工具,能够通过检测压力变化
    的头像 发表于 12-09 18:03 330次阅读

    什么是泄漏电流试验?

    泄漏电流的概念泄漏电流(leakagecurrent)也叫接触电流,是指在没有故障施加电压的情况下,电气中相互绝缘的金属零件之间,或带电零件与接地零件之间,通过其周围介质或绝缘表面所形成的电流。泄漏
    的头像 发表于 11-26 11:48 224次阅读
    什么是<b class='flag-5'>泄漏</b>电流试验?

    从原理聊JVM(一):染色标记和垃圾回收算法

    导读 JAVA简单易用的特性,能够让研发人员在不了解JVM的底层运行机制的情况下依旧能够编写出功能完善的代码。 但是对JVM的理解,是一个程序员普通和优秀的分水岭。全面地了解JVM的工作原理,能够
    的头像 发表于 08-20 15:25 229次阅读
    从原理聊<b class='flag-5'>JVM</b>(一):染色标记和垃圾回收算法

    聊聊JVM如何优化

    首先应该明确的是JVM调优不是常规手段,JVM的存在本身就是为了减轻开发对于内存管理的负担,当出现性能问题的时候第一时间考虑的是代码逻辑与设计方案,以及是否达到依赖中间件的瓶颈,最后才是针对JVM
    的头像 发表于 08-05 17:49 467次阅读
    聊聊<b class='flag-5'>JVM</b>如何优化

    如何检测内存泄漏

    检测内存泄漏是软件开发过程中一项至关重要的任务,它有助于识别和解决那些导致程序占用过多内存资源,从而影响程序性能甚至导致程序崩溃的问题。以下将详细阐述几种常见的内存泄漏检测方法,每种方法都会结合具体步骤和工具进行说明。
    的头像 发表于 07-30 11:50 1822次阅读

    化工厂液体泄漏识别预警算法

    化工厂液体泄漏识别预警基于图像识别算法是计算机视觉的基础算法,例如VGG,GoogLeNet,ResNet等,化工厂液体泄漏识别这类算法主要是判断图片中目标的种类液体泄漏识别预警自动识别监控视频中机械管道是否存在液体
    的头像 发表于 07-03 08:35 400次阅读
    化工厂液体<b class='flag-5'>泄漏</b>识别预警算法

    深入理解Java 8内存管理机制及故障排查实战指南

    Java的自动内存管理机制是由 JVM 中的垃圾收集器实现的,垃圾收集器会定期扫描堆内存中的对象,检测并清除不再使用的对象,以释放内存资源
    的头像 发表于 04-04 08:10 994次阅读
    深入理解Java 8内存管理机制及故障排查实战指南

    密封试验仪为什么会有泄漏

    的数据?简而言之,泄漏是指在一定条件下,根据被测物体的微小漏洞或间隙、蒸汽或液体逃逸的量化表达。这种情况通常是由于物理结构不全面,材料特性不理想造成的。从微观的角度
    的头像 发表于 03-22 11:40 466次阅读
    密封试验仪为什么会有<b class='flag-5'>泄漏</b>量

    C语言内存泄漏问题原理

    内存泄漏问题只有在使用堆内存的时候才会出现,栈内存不存在内存泄漏问题,因为栈内存会自动分配和释放。C语言代码中堆内存的申请函数是malloc。
    发表于 03-19 11:38 521次阅读
    C语言内存<b class='flag-5'>泄漏</b>问题原理

    红外热成像技术在管道泄漏检测中的应用

    在全球范围内,管道泄漏问题一直是一个头疼的问题,它不仅直接威胁到人民的生命财产安全,同时还会导致重大的资源浪费。无论是工业生产中的化工管道,还是日常生活中的供水、供热管道,一旦发生泄漏,后果都是
    的头像 发表于 03-06 11:03 591次阅读
    红外热成像技术在管道<b class='flag-5'>泄漏</b>检测中的应用

    煤气柜泄漏问题如何解决

    电子发烧友网站提供《煤气柜泄漏问题如何解决.docx》资料免费下载
    发表于 03-05 17:49 0次下载

    揭示真空泄漏测试仪的原理和优点

    的检测方案。原理:真空泄漏测试仪的核心是创造一个低压环境,并使用高灵敏度的压力传感器检测小泄漏。在工作过程中,仪器首先将待测产品放置在一个封闭的测试腔中,然后去除腔
    的头像 发表于 03-04 11:57 429次阅读
    揭示真空<b class='flag-5'>泄漏</b>测试仪的原理和优点

    变压器如何减小泄漏感应呢?

    变压器如何减小泄漏感应呢? 变压器是一种用来改变交流电压的重要设备。在变压器中,存在着一种称为泄漏感应的现象。泄漏感应是指变压器在工作过程中,由于磁场的存在产生的感应电动势,但是这部分电动势并不
    的头像 发表于 01-30 17:04 1302次阅读

    什么是气密性泄漏设备

    气密性泄漏设备是指用于检测气体或液体密封性能的设备,其工作原理是通过检测设备内部压力的变化判断密封是否完好。这种设备广泛应用于航空航天、石油化工、电力等领域,用于检测各种管道、阀门、压力容器等设备
    的头像 发表于 01-19 11:34 664次阅读
    什么是气密性<b class='flag-5'>泄漏</b>设备

    直流泄漏和直流耐压 直流耐压为什么采用负极性

    直流泄漏和直流耐压 直流耐压为什么采用负极性  直流泄漏和直流耐压是电力行业中的两个重要概念,它们在电力设备的设计、安装和维护中起着至关重要的作用。直流泄漏指的是直流电系统中的电流泄漏
    的头像 发表于 12-29 11:03 973次阅读