排障 -v2 - 堆外内存泄漏
pmap
首先使用pmap观察内存情况
sudo -u deploy pmap 39 | sort -nk2 | less
可以看到有大量约64M的内存分配:
这个是glibc的feature(http://codearcana.com/posts/2016/07/11/arena-leak-in-glibc.html),可以通过调整 MALLOC_ARENA_MAX
解决(https://devcenter.heroku.com/articles/tuning-glibc-memory-behavior)。
gdb
gdb可以dump进程的内存信息查看,知道内存中是什么内容后,可以进一步排查是否存在泄露的情况。排查另一个oom的问题时,在生产上的机器试验了下,并未查看到有问题的信息,记录下gdb查看内存的使用方法。
(1) 安装gdb: sudo yum install -y gdb
(2) attach: sudo -u deploy gdb --pid={pid}
(3) dump内存: dump memory {path} {start_address} {end_address}(内存地址可以使用pmap或less /proc/{pid}/maps查看)
(4) 查看内存中的字面量: strings {path}
通过上述步骤,可以看到对应内存地址中的字符串,若有堆外内存泄露,一般和DirectBuffer或者Deflater有关,如果打印的字符串中没有嫌疑对象,可能意味着这块内存没有问题。打印内容示例:
perf
目前用到perf主要是看线程栈调用的情况(perf record && perf report),在内存分析上用的较少。
Jemalloc
由于glibc的feature,以及想看Memory Heap分配情况,搜了一下其他的内存分配器,其中Jemalloc既能提升分配效率,又能dump heap,因此首选了Jemalloc试验。
准备工作
(1) 下载Jemalloc: https://github.com/jemalloc/jemalloc/releases
(2) 安装bzip2: sudo yum install -y bzip2
(3) 安装gcc: sudo yum install -y gcc
(4) 安装make: sudo yum install -y make
(5) 安装graphviz: sudo yum install -y graphviz
解压编译
在存放Jemalloc压缩包的目录下执行如下操作,假设jemalloc的版本为{version}
(1) 解压:tar -xvf jemalloc-{version}.tar.bz2
(2) 编译:cd jemalloc-{version} && ./configure --enable-prof && make && sudo make install
(3) 验证:jeprof --version
JVM使用Jemalloc
安装好Jemalloc后,需要在JVM启动时指定使用Jemalloc进行内存分配。
指定方式为在JVM参数中设置如下环境变量(物理机:tomcat/bin/baseenv.sh;docker:tomcat/bin/setenv.sh):
export LD_PRELOAD=/usr/local/lib/libjemalloc.so export MALLOC_CONF=prof:true,lg_prof_interval:30,lg_prof_sample:17,prof_prefix:/mnt/mesos/sandbox/{APPID}/jeprof
参数说明:
LD_PRELOAD: 指定了在JVM启动时需要链接的文件。
MALLOC_CONF: 指定了Heap profiling的参数。
(a) prof:是否需要做Heap profiling。
(b) lg_prof_interval:Heap profiling的间隔,以2为底数的指数,单位为bytes,30意味着每分配(2^30 bytes = 1 GB)就生成一dump文件。
(c) lg_prof_sample:Heap allocation采样的精度,以2为底的指数,单位bytes,17意味着每分配(2^17 bytes = 128 KB)就做一次采样,值越高保真度越低,但程序性能越好。
(d) prof_prefix:Heap dump的路径及前缀,需要确保程序对该路径有写入权限,生成的文件名格式为<prefix>.<pid>.<seq>.i<iseq>.heap。
生成Dump报告
如果上述步骤进行无误,程序运行后一段时间可以在{prof_prefix}指定的目录下看到一些名为jeprof.*.heap的文件。执行如下命令:
jeprof --show_bytes --pdf /usr/java/jdk1.8/bin/java /mnt/mesos/sandbox/{APPID}/jeprof.* > ~/output.pdf
执行完成后就可以看到Heap dump的内容了,通过该内容可以判断是哪里产生了Native Memory分配。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)