首页 > IT职业 > IT职场 > 实战总结|记一次glibc导致的堆外内存泄露
来源:阿里开发者
阿里妹导读
本文记录一次glibc导致的堆外内存泄露的排查过程。
问题现象

发布2天后的内存占用趋势
探索原因一
堆内找到原因


问题解决
是common-division这个包引入的

当前加载俄罗斯(RU)国际地址库,改为一个小国家地址库 以色列(IL)
当前业务使用场景在补发场景下会使用,添加打点日志,确保是否还有业务在使用该服务,没人在用的话,直接下掉(后发现,确还有业务在用呢 🐶)。

发布后短时间内有个内存增长实属正常,后续在做观察。


探索原因二
查看进程内存使用

java 进程内存使用率 84.9%,RES 6.8G。
查看堆内使用情况
当期机器配置为 4Core 8G,堆最大5G,堆使用为不足3G左右。


开始初步怀疑是『堆外内存泄露』
笔者是预发环境,正式环境开启需谨慎,本功能有5%-10%的性能损失!!!
-XX:NativeMemoryTracking=detailjcmd pid VM.native_memory

概念 NMT displays “committed” memory, not "resident" (which you get through the ps command). In other words, a memory page can be committed without considering as a resident (until it directly accessed).
笔者没有使用,因为本功能与NMT作用类似,暂时没有截图了~ rssAnalyzer(内部工具),可以通过oss在预发/线上下载。
堆外内存分析
pmap 查看内存地址/大小分配情况
确认当前JVM使用的内存管理库是哪种
分析是什么地方在用堆外内存。
pmap -x 2531 | sort -k 3 -n -r

剧透: 32位系统中的话,多为1M 64位系统中,多为64M。
strace -f -e"brk,mmap,munmap" -p 2853 原因: 对 heap 的操作,操 作系统提供了 brk()函数,C 运行时库提供了 sbrk()函数;对 mmap 映射区域的操作,操作系 统提供了 mmap()和 munmap()函数。sbrk(),brk() 或者 mmap() 都可以用来向我们的进程添 加额外的虚拟内存。Glibc 同样是使用这些函数向操作系统申请虚拟内存。

cd /opt/taobao/java/binldd java


『V1.0时代』Doug Lea Malloc 在Linux实现,但是在多线程中,存在多线程竞争同一个分配分配区(arena)的阻塞问题。 『V2.0时代』Wolfram Gloger 在 Doug Lea 的基础上改进使得 Glibc 的 malloc 可以支持多线程——ptmalloc。
调用free()时空闲内存块可能放入 pool 中,不一定归还给操作系统。 .收缩堆的条件是当前 free 的块大小加上前后能合并 chunk 的大小大于 64KB、,并且 堆顶的大小达到阈值,才有可能收缩堆,把堆最顶端的空闲内存返回给操作系统。 『V2.0』为了支持多线程,多个线程可以从同一个分配区(arena)中分配内存,ptmalloc 假设线程 A 释放掉一块内存后,线程 B 会申请类似大小的内存,但是 A 释放的内 存跟 B 需要的内存不一定完全相等,可能有一个小的误差,就需要不停地对内存块 作切割和合并。

主分配区:可以通过sbrk/mmap进行分配。 非主分配区,只可以通过mmap进行分配。 其中,mmap每次申请内存的大小为HEAP_MAX_SIZE(32 位系统上默认为 1MB,64 位系统默 认为 64MB)。
哪里在泄露
github下载比较慢,上传到oss,再做下载。
sudo yum install -y git gcc make graphvizwget -P /home/admin/general-aftersales https://xxxx.oss-cn-zhangjiakou.aliyuncs.com/jemalloc-5.3.0.tar.bz2 && \mkdir /home/admin/general-aftersales/jemalloc && \cd /home/admin/general-aftersales/ && \tar -jxcf jemalloc-5.3.0.tar.bz2 && \cd /home/admin/xxxxx/jemalloc-5.3.0/ && \./configure --enable-prof && \make && \sudo make installexport LD_PRELOAD=/usr/local/lib/libjemalloc.so.2 MALLOC_CONF="prof:true,lg_prof_interval:30,lg_prof_sample:17,prof_prefix:/home/admin/general-aftersales/prof_prefix核心配置
make之后,需要启用prof,否则会出现『<jemalloc>: Invalid conf pair: prof:true』类似的关键字 配置环境变量
LD_PRELOAD 挂载本次编译的库 MALLOC_CONF 配置dump内存的时机。
"lg_prof_sample:N",平均每分配出 2^N 个字节 采一次样。当 N = 0 时,意味着每次分配都采样。 "lg_prof_interval:N",分配活动中,每流转 1 « 2^N 个字节,将采样统计数据转储到文件。
./appctl restart
jeprof --svg /opt/taobao/java/bin/java prof_prefix.36090.9.i9.heap > 36090.svg

与参阅文档中结果一致,有通过Java java.util.zip.Inflater 调用JNI申请内存,进而导致了内存泄露。
statck java.util.zip.Inflater <init>




end()是native方法。
二方包扫描

最低版本要求 sar包里的 pandora 版本,要大于等于 2.1.17
问题解决
我们是团队是统一做的基础镜像,找相关的同学做了dockerfile from的升级。



总结
总结的过程,也是学习的过程,上述分析过程欢迎评论探讨。
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/70024922/viewspace-2969435/ ,如需转载,请注明出处,否则将追究法律责任。