关于linux下内存问题排查的工具

对最近linux下排查java内存相关问题的命令做个小的总结

linux系列

top

top -p PID
pid为12415进程的资源消耗情况。这里是以进程为单位。

关于linux下内存问题排查的工具_第1张图片

top -Hp PID

关于linux下内存问题排查的工具_第2张图片

这里是以线程为单位。其中RES看到没有线程占用的内存都是3.3g,是因为JVM内存区域中大部分都是线程共享的。
同时也可以通过shift+h在-p视图下切换至线程视图(set threads On),如下图:
关于linux下内存问题排查的工具_第3张图片

说明: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对一个程序分析一般分为下面几个步骤:

  1. 加入对google-perftools库的依赖
  2. 运行目标程序,并用某种方式启动/终止剖析函数并产生剖析结果
  3. 运行剖析结果转换工具,江不可读的结果转化成某种格式的文档(pdf,txt,image等)

原理:该工具主要利用了unix的一个环境变量LD_PRELOAD,它允许你要加载的动态库优先加载起来,相当于一个Hook,于是可以针对同一个函数可以选择不同的动态库里的实现了,比如googleperftools就是将malloc方法替换成了tcmalloc的实现,这样就可以跟踪内存分配路径了。可以理解为在分配内存的同时增加内存分配跟踪的功能。

下面简单说下针对JVM的分析过程:

  1. 在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】。一般情况下会调小一些。

  1. 运行程序输出heap文件
    在jvm中加入上面的参数后,启动程序。这时候日志中会显示类似下面的内容:
Dumping heap profile to /home/lg/temp/_10030.0001.heap (1755151 MB allocated cumulatively, 1267 MB currently in use)

显示累计的对外内存的分配和当前使用的对外内存的大小。同时配置的对应的目录中会产生.heap文件。接下来的工作就是分析这些文件。

  1. 通过命令行分析文件
    命令:
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相关的工具。

你可能感兴趣的:(关于linux下内存问题排查的工具)