排障 -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分配。

 

posted @ 2022-03-03 16:43  ck_2016  Views(633)  Comments(0Edit  收藏  举报