对最近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进程可能需要进一步借用其他工具来分析。
下一篇再介绍JVM相关的工具。