Java内存泄露问题定位常用命令

jstat -gcutil pid 10000
lsof -p pid
lsof -p pid | wc -l
ls -al /proc/pid/fd  #直接打印出当前此process 所有打开的文件
jmap -histo:live pid > info.log
jmap -dump:live,file=mydumpfile pid
jhat mydumpfile

http://ip:7000 页面直接拉到最下面,可以看出实例引用个数排行,哪里内存泄露。

lsof -p 26674

ls -al /proc/pid/fd
存在大批量的打开anon_inode:[eventpoll]和pipe,如果超过100个eventpoll,
通常情况下是开启了太多HandlerThread/Looper/MessageQueue,线程忘记关闭,或者Looper没有释放。
anon_inode:[eventpoll],这种类型的inode是epoll创建的。
linux下java里的selector实现是epoll结合一个pipe来实现事件通知功能的。所以在NIO程序里,会有anon_inode:[eventpoll]和pipe类型的fd。


Linux中关于文件句柄的注意事项:

1.在linux中,如果一个文件正在被某个进程占用,用户操作rm删除该文件后,我们ls后发现文件已经不存在了,但实际上该文件仍然在磁盘上。直到使用它的进程退出后,文件占用的磁盘空间才会被释放。
在linux中,每个文件都有2个计数器,i_count和i_nlink。i_count表示文件正在被调用的数量。i_nlink表示硬链接的数量。


jmap命令

jmap命令可以用来输出所有内存中对象,甚至可以将VM中的heap以二进制输dump为文本。可以输出某个指定的java进程内存里的所有对象的详情(包括具体对象的数量等)。
jmap输出的heap信息的二进制文件,可以结合jhat等其他内存分析工具进行后续分析。

语法:
jmap [option] <pid> //to connect to running process
jmap [option] <executable <core> //to connect to a core file
jmap [option] [server_id@]<remote server IP or hostname>  //to connect to remote debug server

基本参数:
    <none>               to print same info as Solaris pmap
    -heap                to print java heap summary //打印heap的概要信息,GC使用的算法,heap的配置及wise heap的使用情况
    -histo[:live]        to print histogram of java object heap; if the "live"
                         suboption is specified, only count live objects //打印每个class的实例个数、内存占用、类全名信息。VM的内部类名字开头会加上前缀”*”。如果带live则只统计活的对象数量。
    -clstats             to print class loader statistics
    -finalizerinfo       to print information on objects awaiting finalization //打印正等候回收的对象的信息
    -dump:<dump-options> to dump java heap in hprof binary format
                         dump-options:
                           live         dump only live objects; if not specified,
                                        all objects in the heap are dumped.
                           format=b     binary format
                           file=<file>  dump heap to <file>
                         Example: jmap -dump:live,format=b,file=heap.bin <pid> //二进制文件形式dump输出到文件
    -F                   force. Use with -dump:<dump-options> <pid> or -histo
                         to force a heap dump or histogram when <pid> does not
                         respond. The "live" suboption is not supported
                         in this mode.
    -h | -help           to print this help message
    -J<flag>             to pass <flag> directly to the runtime system

例如:
#jmap -dump:format=b,file=mydumpfile $pid://可以将指定pid进程的内存heap输出到指定文件

#jmap -finalizerinfo  15931
Attaching to process ID 15931, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.77-b03
Number of objects pending for finalization: 0 //等候回收的对象个数为0

注意:
jdk1.8开始,JVM参数进行了调整:

1.PermGen空间被移除了,取而代之的是Metaspace(元空间)。
  因此启动参数需要进行调整:-XX:PermSize=128m -XX:MaxPermSize=512m 修改为 -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=512m 。
  持久代的空间被彻底地删除了,它被一个叫元空间的区域所替代了。持久代删除了之后,很明显,JVM会忽略PermSize和MaxPermSize这两个参数。
  JDK 8的HotSpot JVM现在使用的是本地内存来表示类的元数据,这个区域就叫做元空间。
  
  参数值设置多大合适:程序跑起来以后,通过jstat -gc pid 可以查看MC和MU的情况,根据实际情况进行设置:
  jstat -gc 30648
  S0C    S1C    S0U    S1U      EC       EU        OC         OU       MC     MU    CCSC   CCSU   YGC     YGCT    FGC    FGCT     GCT   
  11776.0 11264.0  0.0   8839.4 1318400.0 651388.6 2682880.0   669041.2  77312.0 74831.9 8960.0 8489.2    871    6.434   3      0.247    6.681
  
  元空间的一些工具
  jmap -permstat改成了jmap -clstats。它用来打印Java堆的类加载器的统计数据。对每一个类加载器,会输出它的名字,是否存活,地址,父类加载器,以及它已经加载的类的数量及大小。除此之外,驻留的字符串(intern)的数量及大小也会打印出来。
  jstat -gc,这个命令输出的是元空间的信息而非持久代的。
  jcmd GC.class_stats提供类元数据大小的详细信息。使用这个功能启动程序时需要加上-XX:+UnlockDiagnosticVMOptions选项。
  
2.CompressedClassSpaceSize = 1073741824 (1024.0MB) 新增了这个。
  CompressedClassSpaceSize 的调优仅在-XX:+UseCompressedClassPointers开启的情况才有效。
  -XX:CompressedClassSpaceSize=1G 这个大小在启动的时候就固定了,因此最好设置得大点。如果没有使用到,就不要进行设置,JVM后续可能会让这个区可以动态增长。该区块不要求连续的区域,只要从基地址可达就行。
  
  查询UseCompressedClassPointers当前是否开启的命令:
  #java -XX:+PrintFlagsInitial | grep UseCompressedClassPointers
     bool UseCompressedClassPointers                = false                               {lp64_product}


# jmap -heap  29675
Attaching to process ID 29675, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.77-b03

using thread-local object allocation.
Parallel GC with 8 thread(s)

Heap Configuration: //堆配置情况
   MinHeapFreeRatio         = 0 //最小堆使用比例
   MaxHeapFreeRatio         = 100 //最大堆可用比例
   MaxHeapSize              = 4120903680 (3930.0MB) //最大堆空间大小
   NewSize                  = 1373634560 (1310.0MB) //新生代分配大小
   MaxNewSize               = 1373634560 (1310.0MB) //最大可新生代分配大小
   OldSize                  = 2747269120 (2620.0MB) //老生代大小
   NewRatio                 = 2 //新生代比例
   SurvivorRatio            = 8 //新生代与suvivor的比例
   MetaspaceSize            = 21807104 (20.796875MB) //jdk 1.8引入的新参数元空间,1.7及老版本用的是PermSize
   CompressedClassSpaceSize = 1073741824 (1024.0MB) //jdk 1.8引入的新的调优参数,仅-XX:+UseCompressedClassPointers开启的情况才有效
   MaxMetaspaceSize         = 536870912 (512.0MB) //jdk 1.8引入的新参数元空间,1.7及老版本用的是MaxPermSize
   G1HeapRegionSize         = 0 (0.0MB) //设置G1平分java堆而产生区域的大小,默认值可以提供最大的工效性。最小值为1M,最大为32M,最多划分1024个,建议使用默认值

Heap Usage: //堆使用情况
PS Young Generation //新生代
Eden Space: //伊甸区
   capacity = 1190133760 (1135.0MB) //容量
   used     = 358255360 (341.658935546875MB)
   free     = 831878400 (793.341064453125MB)
   30.102108858755507% used
From Space: //survior1区
   capacity = 88604672 (84.5MB)
   used     = 62335048 (59.44733428955078MB)
   free     = 26269624 (25.05266571044922MB)
   70.35187489887666% used
To Space:  //survior2区
   capacity = 91750400 (87.5MB)
   used     = 0 (0.0MB)
   free     = 91750400 (87.5MB)
   0.0% used
PS Old Generation //老生代
   capacity = 2747269120 (2620.0MB)
   used     = 56041168 (53.44502258300781MB)
   free     = 2691227952 (2566.554977416992MB)
   2.0398863581300692% used

33056 interned Strings occupying 3268472 bytes.

jstat命令

jstat -gcutil pid 10000

jstat -options:查看选项
[root@standalone fd_test]# jstat -options
-class
-compiler
-gc
-gccapacity
-gccause
-gcmetacapacity
-gcnew
-gcnewcapacity
-gcold
-gcoldcapacity
-gcutil
-printcompilation


jstat -gcnewcapacity:new对象的信息及其占用量
[root@standalone fd_test]# jstat -gcnewcapacity 9813
  NGCMN      NGCMX       NGC      S0CMX     S0C     S1CMX     S1C       ECMX        EC      YGC   FGC 
 1638400.0  1638400.0  1638400.0 545792.0 165376.0 545792.0 167424.0  1637376.0  1303552.0    20    14
[root@standalone fd_test]# 


jstat -gcold:old对象的信息
[root@standalone fd_test]# jstat -gcold 9813
   MC       MU      CCSC     CCSU       OC          OU       YGC    FGC    FGCT     GCT   
 81408.0  78294.9   9472.0   8923.0   3276800.0    320566.8     20    14    1.677    2.579
 
jstat -gcoldcapacity:old对象的信息及其占用量
[root@standalone fd_test]# jstat -gcoldcapacity 9813
   OGCMN       OGCMX        OGC         OC       YGC   FGC    FGCT     GCT   
  3276800.0   3276800.0   3276800.0   3276800.0    20    14    1.677    2.579

jstat -printcompilation:当前VM执行的信息
每1秒打印一次,还可以加上-h5每五行显示一下标题
[root@standalone fd_test]# jstat -printcompilation -h5 9813 1000    
Compiled  Size  Type Method
   15349   4741    1 sun/security/x509/AVA toRFC2253CanonicalString
   15349   4741    1 sun/security/x509/AVA toRFC2253CanonicalString
   15349   4741    1 sun/security/x509/AVA toRFC2253CanonicalString
   15349   4741    1 sun/security/x509/AVA toRFC2253CanonicalString
   15349   4741    1 sun/security/x509/AVA toRFC2253CanonicalString
Compiled  Size  Type Method
   15349   4741    1 sun/security/x509/AVA toRFC2253CanonicalString
   15349   4741    1 sun/security/x509/AVA toRFC2253CanonicalString
   15354   1793    1 org/pentaho/di/core/logging/LogbackEventListener formatterMsg
   15356    127    1 java/util/Collections$UnmodifiableMap$UnmodifiableEntrySet iterator
   15356    127    1 java/util/Collections$UnmodifiableMap$UnmodifiableEntrySet iterator
Compiled  Size  Type Method
   15356    127    1 java/util/Collections$UnmodifiableMap$UnmodifiableEntrySet iterator
   15356    127    1 java/util/Collections$UnmodifiableMap$UnmodifiableEntrySet iterator
   15356    127    1 java/util/Collections$UnmodifiableMap$UnmodifiableEntrySet iterator
   15356    127    1 java/util/Collections$UnmodifiableMap$UnmodifiableEntrySet iterator
   15356    127    1 java/util/Collections$UnmodifiableMap$UnmodifiableEntrySet iterator

jstack命令
如果java程序崩溃生成core文件,jstack工具可以用来获得core文件的java stack和native stack的信息,从而可以轻松地知道java程序是如何崩溃和在程序何处发生问题。
jstack用于打印出给定的java进程ID或core file或远程调试服务的Java堆栈信息,如果是在64位机器上,需要指定选项"-J-d64"。
一般情况下,通过jstack输出的线程信息主要包括:jvm自身线程、用户线程等。其中jvm线程会在jvm启动时就会存在。对于用户线程则是在用户访问时才会生成。

Usage:
    jstack [-l] <pid>
        (to connect to running process)
    jstack -F [-m] [-l] <pid>
        (to connect to a hung process)
    jstack [-m] [-l] <executable> <core>
        (to connect to a core file)
    jstack [-m] [-l] [server_id@]<remote server IP or hostname>
        (to connect to a remote debug server)

Options:
    -F  to force a thread dump. Use when jstack <pid> does not respond (process is hung)
    -m  to print both java and native frames (mixed mode)
    -l  long listing. Prints additional information about locks
    -h or -help to print this help message
    
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值