Jmap

用途:

查询当前进程的内存情况

使用方法

查看实例个数以及所占用的内存大小

  1. # 输出到控制条
  2. jmap -histo pid
  3. # 输出到文件
  4. jmap -histo pid > ./log.txt

输出结果

列名参数解释:

  • num:序号
  • instances:所包含的实例数
  • bytes:所占用的内存大小(byte)
  • class name:该内存所对应的类名
    • ([代表一维数组,[[ 代表二维数组)
    • [I 是int 数组,[C是char数组,[B 是byte数组
    • [[I是int[][]数组

image.png

查看堆内存的信息

  1. jmap -heap pid

输出结果

  1. Attaching to process ID 4084, please wait...
  2. Debugger attached successfully.
  3. Server compiler detected.
  4. JVM version is 25.60-b23
  5. using thread-local object allocation.
  6. # 并行垃圾收集器的线程(默认是CPU核数)
  7. Parallel GC with 2 thread(s)
  8. Heap Configuration:
  9. MinHeapFreeRatio = 0
  10. MaxHeapFreeRatio = 100
  11. MaxHeapSize = 994050048 (948.0MB) //最大的堆空间,默认1/4 -Xmx
  12. NewSize = 20971520 (20.0MB) // 新生代的空间
  13. MaxNewSize = 331350016 (316.0MB) // 最大的新生代空间,默认整个堆的1/3
  14. OldSize = 41943040 (40.0MB) // 老年代的大小
  15. NewRatio = 2 // 新生代的比例与老年代的比例
  16. SurvivorRatio = 8 // 伊甸园与幸存者区的比例
  17. MetaspaceSize = 21807104 (20.796875MB) // 元空间的大小,默认21M
  18. CompressedClassSpaceSize = 1073741824 (1024.0MB) // 类指针压缩空间大小,默认1G
  19. MaxMetaspaceSize = 17592186044415 MB // 最大的元空间大小,默认无限大。。。
  20. G1HeapRegionSize = 0 (0.0MB) // G1垃圾收集器的每块region的大小
  21. Heap Usage:
  22. PS Young Generation
  23. Eden Space: // 伊甸园的容量
  24. capacity = 80740352 (77.0MB)
  25. used = 42850680 (40.86559295654297MB)
  26. free = 37889672 (36.13440704345703MB)
  27. 53.072198644861% used
  28. From Space: // from 区的幸存者区
  29. capacity = 524288 (0.5MB)
  30. used = 294912 (0.28125MB)
  31. free = 229376 (0.21875MB)
  32. 56.25% used
  33. To Space: // to 区的幸存者区
  34. capacity = 524288 (0.5MB)
  35. used = 0 (0.0MB)
  36. free = 524288 (0.5MB)
  37. 0.0% used
  38. PS Old Generation // 老年代
  39. capacity = 76021760 (72.5MB)
  40. used = 26281512 (25.064002990722656MB)
  41. free = 49740248 (47.435997009277344MB)
  42. 34.57103860789332% used
  43. 19613 interned Strings occupying 1885552 bytes

dump 堆内存

  1. [root@localhost ~]# jmap -dump:format=b,file=test.hprof 4084
  2. Dumping heap to /root/test.hprof ...
  3. Heap dump file created

除了手动到处dump文件之外,还可以通过设置内存溢出(OOM)时自动导出Dump文件,用于分析OOM时的内存情况

  • -XX:+HeapDumpOnOutOfMemoryError
  • -XX:HeapDumpPath=./ (指定dump导入的路径)

导出的Dump文件,可以通过jvisualvm工具打开,分析其中的内存情况
image.png


Jstack

Jstack 命令可以用来查询进程中的死锁

详细的步骤如下

死锁代码演示

  1. public class Test2 {
  2. public static void main(String[] args) {
  3. String lockA = "lockA";
  4. String lockB = "lockB";
  5. new Thread(new MyDeadLock(lockA, lockB), "threadA").start();
  6. new Thread(new MyDeadLock(lockB, lockA), "threadB").start();
  7. }
  8. }
  9. class MyDeadLock implements Runnable {
  10. private final String lockA;
  11. private final String lockB;
  12. public MyDeadLock(String lockA, String lockB) {
  13. this.lockA = lockA;
  14. this.lockB = lockB;
  15. }
  16. @Override
  17. public void run() {
  18. synchronized (lockA) {
  19. System.out.println(Thread.currentThread().getName() + "\t持有" + lockA);
  20. System.out.println(Thread.currentThread().getName() + "\t尝试获取" + lockB);
  21. synchronized (lockB) {
  22. }
  23. }
  24. }
  25. }

通过Jstack命令进行查询死锁

  1. jstack pid

输出结果

  1. "threadB" #13 prio=5 os_prio=0 tid=0x0000000023a69000 nid=0x43d4 waiting for monitor entry [0x00000000249df000]
  2. java.lang.Thread.State: BLOCKED (on object monitor)
  3. at test.MyDeadLock.run(Test2.java:43)
  4. - waiting to lock <0x0000000740aea228> (a java.lang.String)
  5. - locked <0x0000000740aea260> (a java.lang.String)
  6. at java.lang.Thread.run(Thread.java:748)
  7. "threadA" #12 prio=5 os_prio=0 tid=0x0000000023a65800 nid=0x5c84 waiting for monitor entry [0x00000000248df000]
  8. java.lang.Thread.State: BLOCKED (on object monitor)
  9. at test.MyDeadLock.run(Test2.java:43)
  10. - waiting to lock <0x0000000740aea260> (a java.lang.String)
  11. - locked <0x0000000740aea228> (a java.lang.String)
  12. at java.lang.Thread.run(Thread.java:748)
  • threadB: 线程名字
  • prio: 优先级
  • os_prio:操作系统的优先级
  • tid:线程id
  • nid:线程标识
  • BLOCKED:线程状态 ```shell

    Found one Java-level deadlock:

    “threadB”: waiting to lock monitor 0x0000000021ab0a78 (object 0x0000000740aea228, a java.lang.String), which is held by “threadA” “threadA”: waiting to lock monitor 0x0000000023a6be18 (object 0x0000000740aea260, a java.lang.String), which is held by “threadB”

Java stack information for the threads listed above:

“threadB”: at test.MyDeadLock.run(Test2.java:43)

  1. - waiting to lock <0x0000000740aea228> (a java.lang.String)
  2. - locked <0x0000000740aea260> (a java.lang.String)
  3. at java.lang.Thread.run(Thread.java:748)

“threadA”: at test.MyDeadLock.run(Test2.java:43)

  1. - waiting to lock <0x0000000740aea260> (a java.lang.String)
  2. - locked <0x0000000740aea228> (a java.lang.String)
  3. at java.lang.Thread.run(Thread.java:748)

Found 1 deadlock.

  1. 找出了一个Java级别的死锁,具体的堆栈信息也已经打印,可以快速准确的定位到死锁的位置<br />**另外,也可以通过jvisualvm工具,找到对应的java进程,jvisualvm可以自动的监测死锁**<br />![image.png](https://cdn.nlark.com/yuque/0/2020/png/1538293/1601350916141-31109e65-a707-4009-aa0e-5dad3305309f.png#align=left&display=inline&height=493&margin=%5Bobject%20Object%5D&name=image.png&originHeight=493&originWidth=1609&size=65748&status=done&style=none&width=1609)<br />点击线程Dump之后,会看到与上述命令行中打印的信息相同,也可准确的定位到死锁的位置<br />![image.png](https://cdn.nlark.com/yuque/0/2020/png/1538293/1601351030339-7a5ddd6a-13a2-41e1-ae93-edd968ff2772.png#align=left&display=inline&height=937&margin=%5Bobject%20Object%5D&name=image.png&originHeight=937&originWidth=678&size=65415&status=done&style=none&width=678)
  2. <a name="sJvXv"></a>
  3. ## Jstack查询CPU占用最高的线程
  4. <a name="dPXKV"></a>
  5. ### 面试题:生产服务器**出现CPU占用过高,请谈谈你的分析思路和定位**
  6. 1. 通过top 命令查询出占用cpu最高的进程
  7. ![image.png](https://cdn.nlark.com/yuque/0/2020/png/1538293/1601351940395-a9b3e752-3acf-49cc-b9d0-cdc31a8980e1.png#align=left&display=inline&height=89&margin=%5Bobject%20Object%5D&name=image.png&originHeight=89&originWidth=1240&size=41369&status=done&style=none&width=1240)
  8. 2. ps -mp 进程编号 -o Thread.tid,time 查询出这个线程所占用的线程,找出cpu占用高的线程
  9. ![image.png](https://cdn.nlark.com/yuque/0/2020/png/1538293/1601351860515-5672e4ea-869b-4258-83d1-7c90b412938e.png#align=left&display=inline&height=468&margin=%5Bobject%20Object%5D&name=image.png&originHeight=468&originWidth=938&size=231682&status=done&style=none&width=938)
  10. 3. 将查询出来的线程id转成16进制
  11. ![image.png](https://cdn.nlark.com/yuque/0/2020/png/1538293/1601351873891-4b78cffc-c9ab-4a28-8be1-6a8941e5d170.png#align=left&display=inline&height=76&margin=%5Bobject%20Object%5D&name=image.png&originHeight=76&originWidth=670&size=20599&status=done&style=none&width=670)
  12. 4. 通过jstack命令,找出对应的堆栈
  13. 公式: jstack 进程id |grep 线程16进制 -A 行数
  14. ```shell
  15. jstack 3896|grep f39 -A 60

image.png
通过全限定类名,就可以找到对应的代码,准确定位


JInfo

用于查看当前运行的Java程序的参数

查看JVM运行时的参数 jinfo -flags pid

  1. [root@localhost ~]# jinfo -flags 4084
  2. Attaching to process ID 4084, please wait...
  3. Debugger attached successfully.
  4. Server compiler detected.
  5. JVM version is 25.60-b23
  6. Non-default VM flags: -XX:CICompilerCount=2 -XX:InitialHeapSize=62914560
  7. -XX:MaxHeapSize=994050048 -XX:MaxNewSize=331350016 -XX:MinHeapDeltaBytes=524288
  8. -XX:NewSize=20971520 -XX:OldSize=41943040 -XX:+UseCompressedClassPointers
  9. -XX:+UseCompressedOops -XX:+UseFastUnorderedTimeStamps -XX:+UseParallelGC
  10. Command line:

查看JVM的系统参数 jinfo -sysprops pid

可以查看jdk版本啊,jdk所在目录啊,操作系统啊等等信息。
image.png

Jstat

用于查询堆内存中各个区中的使用情况
公式:jstat [-option] [进程id] [时间间隔(毫秒)] [查询次数]

jstat -gc pid interval count

可以用来获取当前内存的使用情况,可以GC垃圾回收的次数以及时间

  1. [root@localhost ~]# jstat -gc 4084 1000 5
  2. S0C S1C S0U S1U EC EU OC OU MC MU CCSC CCSU YGC YGCT FGC FGCT GCT
  3. 512.0 512.0 0.0 256.0 84480.0 45960.3 74240.0 25809.5 65712.0 62406.9 8700.0 8114.6 3491 9.827 4 0.338 10.166
  4. 512.0 512.0 0.0 256.0 84480.0 45960.3 74240.0 25809.5 65712.0 62406.9 8700.0 8114.6 3491 9.827 4 0.338 10.166
  5. 512.0 512.0 0.0 256.0 84480.0 45968.9 74240.0 25809.5 65712.0 62406.9 8700.0 8114.6 3491 9.827 4 0.338 10.166
  6. 512.0 512.0 0.0 256.0 84480.0 45968.9 74240.0 25809.5 65712.0 62406.9 8700.0 8114.6 3491 9.827 4 0.338 10.166
  7. 512.0 512.0 0.0 256.0 84480.0 47031.8 74240.0 25809.5 65712.0 62406.9 8700.0 8114.6 3491 9.827 4 0.338 10.166

各个参数解释:

  • SOC(survivors 0 count):幸存者0区的总大小
  • S1C(survivors 1 count):幸存者1区的总大小
  • S0U(survivors 0 used):幸存者0区的已使用大小
  • S1U(survivors 1 used):幸存者1区的已使用大小
  • EC(eden count):伊甸园的总大小
  • EU(edeb used):伊甸园的已使用大小
  • OC(old count):老年代的总大小
  • OU(old used):老年代的已使用大小
  • MC(metaspace count):元空间的总大小
  • MU(metaspace used):元空间的已使用大小
  • CCSC(compress class space count):压缩类的总空间大小
  • CCSU(compress class space used):压缩类的已使用大小
  • YGC(young gc count):Young GC的次数
  • YGCT(young gc time):Young GC的总耗时
  • FGC(full gc count):FULL GC的次数
  • FGCT(full gc time): FULL GC的总耗时
  • GCT(gc time):总的垃圾回收的耗时

    jstat -gccapacity pid

    用来获取当前堆的内存情况

    1. [root@localhost ~]# jstat -gccapacity 4084
    2. NGCMN NGCMX NGC S0C S1C EC OGCMN OGCMX OGC OC MCMN MCMX MC CCSMN CCSMX CCSC YGC FGC
    3. 20480.0 323584.0 236032.0 512.0 512.0 89088.0 40960.0 647168.0 74240.0 74240.0 0.0 1105920.0 65712.0 0.0 1048576.0 8700.0 3500 4

    各个参数解释:

  • NGCMN:新生代的最小容量

  • NGCNX: 新生代的最大容量
  • NGC: 新生代当前的容量
  • S0C: 幸存者0区当前的容量
  • S1C: 幸存者1区当前的容量
  • EC: 伊甸园区当前的容量
  • OGCMN:老年代的最小容量
  • OGCMX:老年代的最大容量
  • OGC: 老年代的当前大小
  • OC: 老年代的当前大小
  • MCMN: 元空间的最小容量
  • MCMX: 元空间的最大容量
  • MC: 元空间的当前大小
  • CCSMN:压缩类空间的最小容量
  • CCSMX: 压缩类空间的最大容量
  • CCSC: 压缩类空间的当前大小
  • YGC: Young GC 的次数
  • FGC: FULL GC的次数

    jstat -gcnew pid

    用于新生代垃圾回收统计

    1. [root@localhost ~]# jstat -gcnew 4084
    2. S0C S1C S0U S1U TT MTT DSS EC EU YGC YGCT
    3. 512.0 512.0 352.0 0.0 15 15 512.0 90112.0 84565.4 3502 9.860

    各个参数解释:

  • S0C: 幸存者0区的容量

  • S1C: 幸存者1区的容量
  • S0U: 幸存者0区已使用的大小
  • S1U: 幸存者1区已使用的大小
  • TT: 对象在新生代的存活次数
  • MTT:对象在新生代的最大存活次数
  • DSS: 期望的幸存者区大小
  • EC: 伊甸园的大小
  • EU: 伊甸园的使用大小
  • YGC: Young GC的次数
  • YGCT:YoungGC的消耗时间

    jstat -gcnewcapacity pid

    新生代的内存统计

    1. NGCMN NGCMX NGC S0CMX S0C S1CMX S1C ECMX EC YGC FGC
    2. 20480.0 323584.0 236032.0 107520.0 512.0 107520.0 512.0 322560.0 90624.0 3503 4

    各个参数解释:

  • NGCMN:新生代的最小容量

  • NGCMX:新生代的最大容量
  • NGC: 新生代的当前容量
  • S0CMX: 幸存者0区的最大容量
  • S0C: 幸存者0区的当前容量
  • S1CMX: 幸存者1区的最大容量
  • S1C: 幸存者1区的当前容量
  • ECMX: 伊甸园区的最大容量
  • EC: 伊甸园区的当前容量
  • YGC: Young GC的次数
  • FGC: FULL GC的次数

    jstat -gcold pid

    用于老年代垃圾回收统计

    1. MC MU CCSC CCSU OC OU YGC FGC FGCT GCT
    2. 65712.0 62406.9 8700.0 8114.6 74240.0 26025.5 3504 4 0.338 10.205

    各个参数解释:

  • MC: 元空间的容量

  • MU: 元空间的已使用大小
  • CCSC: 压缩类空间的容量
  • CCSU: 压缩类空间的已使用大小
  • OC: 老年代的容量
  • OU: 老年代的已使用大小
  • YGC: Young GC的次数
  • FGC: FULL GC的次数
  • FGCT: FULL GC的总耗时
  • GCT: GC的总耗时

    jstat -gcoldcapacity pid

    老年代内存统计

    1. OGCMN OGCMX OGC OC YGC FGC FGCT GCT
    2. 40960.0 647168.0 74240.0 74240.0 3505 4 0.338 10.207

    各个参数解释:

  • OGCMN: 老年代的最小容量

  • OGCMX: 老年代的最大容量
  • OGC: 老年代的当前容量
  • OC: 老年代的当前容量
  • YGC: Young GC的次数
  • FGC: FULL GC的次数
  • FGCT: FULL GC的消耗时间
  • GCT: 垃圾回收的总耗时

    jstat -gcmetacapacity pid

    元数据的空间统计

    1. MCMN MCMX MC CCSMN CCSMX CCSC YGC FGC FGCT GCT
    2. 0.0 1105920.0 65712.0 0.0 1048576.0 8700.0 3505 4 0.338 10.207

    各个参数解释:

  • MCMN: 元空间的最小容量

  • MCMX: 元空间的最大容量
  • MC: 元空间的当前使用容量
  • CCSMN: 压缩类空间的最小容量
  • CCSMX: 压缩类空间的最大容量
  • CCSC: 压缩类空间的当前容量
  • YGC: Young GC的次数
  • FGC: FULL GC的次数
  • FGCT: FULL GC的消耗时间
  • GCT: 垃圾回收的总耗时

    jstat -gcutil pid

    1. S0 S1 E O M CCS YGC YGCT FGC FGCT GCT
    2. 0.00 68.75 86.91 35.08 94.97 93.27 3505 9.869 4 0.338 10.207

    各个参数解释:

  • S0: 幸存者0区的大小

  • S1: 幸存者1区的大小
  • E: 伊甸园区的大小
  • O: 老年代的大小
  • M: 元空间的大小
  • CCS: 压缩类空间的大小
  • YGC: Young GC的次数
  • YGCT: Young GC的消耗时间
  • FGC: FULL GC的次数
  • FGCT: FULL GC的消耗时间
  • GCT: 垃圾回收的总时间