关于linux下内存问题排查的工具
对最近linux下排查java内存相关问题的命令做个小的总结
linux系列
top
top -p PID
pid为12415进程的资源消耗情况。这里是以进程为单位。
top -Hp PID
这里是以线程为单位。其中RES看到没有线程占用的内存都是3.3g,是因为JVM内存区域中大部分都是线程共享的。
同时也可以通过shift+h在-p视图下切换至线程视图(set threads On),如下图:
说明:top命令的TIME/TIME+是指的进程/线程所使用的CPU时间,不是进程/线程启动到现在的时间,因此,如果一个进程/线程使用的cpu很少,那即使这个进程/线程已经存在N长时间,TIME/TIME+也是很小的数值。
/proc/$pid/status
[#]$ cat /proc/12415/status
Name: java
State: S (sleeping)
Tgid: 12415
Pid: 12415
PPid: 1
TracerPid: 0
Uid: 502 502 502 502
Gid: 501 501 501 501
Utrace: 0
FDSize: 512
Groups: 501
VmPeak: 6734784 kB
VmSize: 6732236 kB
VmLck: 0 kB
VmHWM: 3476100 kB
VmRSS: 3473752 kB
VmData: 6560732 kB
VmStk: 88 kB
VmExe: 4 kB
VmLib: 17620 kB
VmPTE: 7404 kB
VmSwap: 0 kB
Threads: 108
SigQ: 0/23301
SigPnd: 0000000000000000
ShdPnd: 0000000000000000
SigBlk: 0000000000000000
SigIgn: 0000000000000002
SigCgt: 2000000181005ccd
CapInh: 0000000000000000
CapPrm: 0000000000000000
CapEff: 0000000000000000
CapBnd: ffffffffffffffff
Cpus_allowed: f
Cpus_allowed_list: 0-3
Mems_allowed: 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000001
Mems_allowed_list: 0
voluntary_ctxt_switches: 1
nonvoluntary_ctxt_switches: 1
其中VmRSS表示就是占用的物理内存。Threads表示当前开启的线程数。
特别说明RSS【实际使用物理内存】的含义:resident set size, the non-swapped physical memory that a task has used (in kiloBytes). (alias rssize, rsz).
pmap
[~]$ pmap -d 12415
12415: /usr/local/env/jdk1.8/bin/java -server -Xmx1024M -Xms1024M -Xmn512M -XX:MaxMetaspaceSize=128M -XX:MetaspaceSize=128M -XX:MaxDirectMemorySize=128M -XX:+UseConcMarkSweepGC -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=70 -XX:+ExplicitGCInvokesConcurrentAndUnloadsClasses -XX:+CMSClassUnloadingEnabled -XX:+ParallelRefProcEnabled -XX:+CMSScavengeBeforeRemark -XX:-HeapDumpOnOutOfMemoryError -XX:+UseFastAccessorMethods -Xss256k -XX:SurvivorRatio=8 -XX:MaxTenuringThreshold=7 -XX:GCTimeRatio
Address Kbytes Mode Offset Device Mapping
0000000000400000 4 r-x-- 0000000000000000 0fc:00001 java
0000000000600000 4 rw--- 0000000000000000 0fc:00001 java
000000000116d000 996 rw--- 0000000000000000 000:00000 [ anon ]
00000000c0000000 1063680 rw--- 0000000000000000 000:00000 [ anon ]
0000000100ec0000 1033472 ----- 0000000000000000 000:00000 [ anon ]
0000003112e00000 88 r-x-- 0000000000000000 0fc:00001 libgcc_s-4.4.7-20120601.so.1
0000003112e16000 2044 ----- 0000000000016000 0fc:00001 libgcc_s-4.4.7-20120601.so.1
0000003113015000 4 rw--- 0000000000015000 0fc:00001 libgcc_s-4.4.7-20120601.so.1
00007f2c7d4a8000 12 r--s- 0000000000020000 0fc:00001 start.jar
00007f2c7d4ab000 4 rw--- 0000000000000000 000:00000 [ anon ]
00007f2c7d4ac000 4 r---- 0000000000000000 000:00000 [ anon ]
00007f2c7d4ad000 4 rw--- 0000000000000000 000:00000 [ anon ]
00007ffddeeed000 84 rw--- 0000000000000000 000:00000 [ stack ]
00007ffddef12000 4 r-x-- 0000000000000000 000:00000 [ anon ]
ffffffffff600000 4 r-x-- 0000000000000000 000:00000 [ anon ]
mapped: 6732236K writeable/private: 3786640K shared: 10820K
为方便展示省去中间部分内容
这里看pmap重点是最后一行,进程实际使用的物理内存是writeable/private: 3786640K。
其他几个点是什么意思呢?linux 会把一些shared libraries 载入到内存中,在pmap 的输出中,这些shared libraries 的名字通常是 lib*.so 。如 libX11.so.6.2.0 。这个 libX11.so.6.2.0 会被很多process load 到自己的运行环境中。上面展示的mapped的内存就包含这部分和其他进程共享的内存【pmap is reporting virtual memory statistics which match top VIRT column . This is including data shared with other processes and other pages stored on disk.】。
google perf
gperftools是google开发的一款非常实用的工具集,主要包括:性能优异的malloc free内存分配器tcmalloc;基于tcmalloc的堆内存检测和内存泄漏分析工具heap-profiler,heap-checker;基于tcmalloc实现的程序CPU性能监测工具cpu-profiler。可以对CPU时间片、内存等系统资源的分配合使用进行分析。使用perf对一个程序分析一般分为下面几个步骤:
- 加入对google-perftools库的依赖
- 运行目标程序,并用某种方式启动/终止剖析函数并产生剖析结果
- 运行剖析结果转换工具,江不可读的结果转化成某种格式的文档(pdf,txt,image等)
原理:该工具主要利用了unix的一个环境变量LD_PRELOAD,它允许你要加载的动态库优先加载起来,相当于一个Hook,于是可以针对同一个函数可以选择不同的动态库里的实现了,比如googleperftools就是将malloc方法替换成了tcmalloc的实现,这样就可以跟踪内存分配路径了。可以理解为在分配内存的同时增加内存分配跟踪的功能。
下面简单说下针对JVM的分析过程:
- 在JVM参数中增加下面的配置:
export LD_PRELOAD=/usr/lib64/libtcmalloc.so
export HEAPPROFILE=/home/lg/temp
export HEAP_PROFILE_ALLOCATION_INTERVAL= 1073741824
LD_PRELOAD
perftools一切都是以tcmalloc为基础。这里指定tcmalloc的安装位置;
HEAPPROFILE
指定heap profile存放的位置
HEAP_PROFILE_ALLOCATION_INTERVAL
每当一定量的内存被新申请分配出来时,就会输出profile文件,这个变量值就是控制多少字节。默认值是102410241024byte【1G】。一般情况下会调小一些。
- 运行程序输出heap文件
在jvm中加入上面的参数后,启动程序。这时候日志中会显示类似下面的内容:
Dumping heap profile to /home/lg/temp/_10030.0001.heap (1755151 MB allocated cumulatively, 1267 MB currently in use)
显示累计的对外内存的分配和当前使用的对外内存的大小。同时配置的对应的目录中会产生.heap文件。接下来的工作就是分析这些文件。
- 通过命令行分析文件
命令:
pprof --text /usr/local/env/jdk1.8/bin/java _10030.0001.heap
输出结果:
Using local file /usr/local/env/jdk1.8/bin/java.
Using local file _10030.0001.heap.
Total: 0.1 MB
0.0 83.9% 83.9% 0.1 99.9% __FRAME_END__
0.0 6.1% 90.0% 0.0 6.1% read_alias_file
0.0 5.6% 95.6% 0.0 5.6% _nl_intern_locale_data
0.0 3.1% 98.6% 0.0 3.1% _nl_make_l10nflist
0.0 0.7% 99.3% 0.0 0.7% __gconv_lookup_cache
0.0 0.3% 99.6% 0.0 0.3% strdup
0.0 0.2% 99.8% 0.0 5.8% _nl_load_locale_from_archive
0.0 0.1% 99.9% 0.0 0.7% __wcsmbs_load_conv
0.0 0.1% 99.9% 0.0 0.1% std::basic_string::_Rep::_S_create
0.0 0.0% 100.0% 0.0 0.0% set_binding_values
0.0 0.0% 100.0% 0.0 0.0% new_composite_name
0.0 0.0% 100.0% 0.0 0.0% 00007f5e3a5f3de1
0.0 0.0% 100.0% 0.0 0.1% 00007f5e3a5f3dc0
0.0 0.0% 100.0% 0.0 0.1% 00007f5e3a602405
0.0 0.0% 100.0% 0.0 0.1% 0x00007ffc250bc6e0
0.0 0.0% 100.0% 0.0 0.1% 0x2f6c61636f6c2f71
0.0 0.0% 100.0% 0.0 9.2% __dcigettext
0.0 0.0% 100.0% 0.0 0.7% __gconv_find_transform
0.0 0.0% 100.0% 0.1 89.5% __libc_start_main
0.0 0.0% 100.0% 0.0 0.1% _init
0.0 0.0% 100.0% 0.0 0.1% _init (inline)
0.0 0.0% 100.0% 0.0 6.1% _nl_expand_alias
0.0 0.0% 100.0% 0.0 9.2% _nl_find_domain
0.0 0.0% 100.0% 0.0 5.8% _nl_find_locale
0.0 0.0% 100.0% 0.0 0.0% bindtextdomain
0.0 0.0% 100.0% 0.0 0.7% mblen
0.0 0.0% 100.0% 0.0 0.7% mbrtowc
0.0 0.0% 100.0% 0.0 6.1% setlocale
0.0 0.0% 100.0% 0.0 0.1% std::basic_string::basic_string
0.0 0.0% 100.0% 0.0 0.1% std::basic_string::copy
0.0 0.0% 100.0% 0.0 7.6% strerror
0.0 0.0% 100.0% 0.0 7.6% strerror_r
0.0 0.0% 100.0% 0.0 0.0% textdomain
以上不是实际问题的数据
结果代表的含义:
- c1 Number of profiling samples in this function(函数分析样本数量)
- c2 Percentage of profiling samples in this function(函数分析样本的百分比)
- c3 Percentage of profiling samples in the functions printed so far(
到目前为止打印的函数中的分析样本的百分比) - c4 Number of profiling samples in this function and its callees(
此函数及其被调用者的性能分析样本数) - c5 Percentage of profiling samples in this function and its callees(此函数及其被调用者的性能分析样本的百分比)
- c5 Function name
通过perftools可以定位可能引起问题的函数或者有嫌疑的内存地址。针对JVM进程可能需要进一步借用其他工具来分析。
参考链接:
heap_checker
perftoos使用心得
下一篇再介绍JVM相关的工具。