【JVM优化】JVM自带性能调优工具

Love The Way You Lie 2023-08-17 16:50 182阅读 0赞

前提概要:

JDK本身提供了很多方便的JVM性能调优监控工具,有jps、jstack、jmap、jhat、jstat、hprof,VisualVM和jConsole等工具,VisualVM和jConsole作为其中两个可视化工具,当然是最直观最易懂的,不过在linux环境一些无图形界面的操作系统上,其他的小工具就会显得格外的实在。

一般企业级Java开发中,最常遇到的问题:内存不足、内存泄露、线程死锁、Java进程消耗CPU过高。 对于大多数开发人员基本都归结与程序的缺陷,但是从哪里入手找到这些问题,似乎并不是一个普通开发所擅长解决的事情。下面就来告诉你如何通过以上小工具来分析和定位。

一、 jps(Java Virtual Machine Process Status Tool)

语法格式:

  1. jps [options] [hostid]
  2. [options]:
  3. -q 不输出类名、Jar名和传入main方法的参数
  4. -m 输出传入main方法的参数
  5. -l 输出main类或Jar的全限名
  6. -v 输出传入JVM的参数
  7. [hostid]
  8. 如果不指定hostid就默认为当前主机或服务器。

示例:

  1. root@dr-574cb5cf8f-82jdb:/# jps -v
  2. 6 jar -Xms6G -Xmx6G -XX:+UseG1GC -XX:MaxGCPauseMillis=300 -XX:ParallelGCThreads=4 -XX:InitiatingHeapOccupancyPercent=40 -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -Xloggc:/nas/logs/dr/heap_trace.txt -XX:+HeapDumpOnOutOfMemoryError -XX:+HeapDumpBeforeFullGC -XX:+HeapDumpAfterFullGC -XX:HeapDumpPath=/nas/logs/dr/heap_dump.hprof -Dapp.name=data-retrieval
  3. 104 Jps -Dapplication.home=/usr/lib/jvm/java-8-openjdk-amd64 -Xms8m

二、 jstack

jstack主要用来查看某个Java进程内的线程堆栈信息。
语法格式:

  1. jstack [option] pid
  2. jstack [option] executable core
  3. jstack [option] [server-id@]remote-hostname-or-ip
  4. [option]:
  5. -l long listings,会打印出额外的锁信息,在发生死锁时可以用jstack -l pid来观察锁持有情况
  6. -m mixed mode,不仅会输出Java堆栈信息,还会输出C/C++堆栈信息(比如Native方法)
  7. -F 当使用jstack <pid>无响应时,强制输出线程堆栈。
  8. jstack可以定位到线程堆栈,根据堆栈信息我们可以定位到具体代码,所以它在JVM性能调优中使用得非常多。

示例:
找出某个Java进程中最耗费CPU的Java线程并定位堆栈信息:
1、先找出Java进程ID

  1. root@dr-6fbc7fd678-t4vdg:/# jps -ml
  2. 6 data-retrieval-runner-1.0.jar
  3. 24473 sun.tools.jps.Jps -ml
  4. root@dr-6fbc7fd678-t4vdg:/#
  5. 这里的java进程PID6

2.找出该进程内最耗费CPU的线程:

  1. top -Hp 6
  2. top - 17:08:37 up 47 days, 3:21, 0 users, load average: 0.16, 0.12, 0.29
  3. KiB Mem: 32779828 total, 25450424 used, 7329404 free, 95160 buffers
  4. KiB Swap: 0 total, 0 used, 0 free. 3124264 cached Mem
  5. PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
  6. 81 root 20 0 13.980g 7.683g 11460 S 0.0 24.6 10:12.86 java
  7. 84 root 20 0 13.980g 7.683g 11460 S 0.0 24.6 9:42.66 java
  8. 79 root 20 0 13.980g 7.683g 11460 S 0.0 24.6 9:28.21 java
  9. 83 root 20 0 13.980g 7.683g 11460 S 0.0 24.6 8:49.11 java
  10. 78 root 20 0 13.980g 7.683g 11460 S 0.0 24.6 8:03.91 java
  11. 82 root 20 0 13.980g 7.683g 11460 S 0.0 24.6 8:03.83 java
  12. 87 root 20 0 13.980g 7.683g 11460 S 0.0 24.6 7:40.32 java
  13. top命令后,按快捷T按照时间排序。这里最耗性能的线程为81号线程。

3. 将十进制的线程号转化为十六进制

  1. root@dr-6fbc7fd678-t4vdg:/# printf "%x\n" 81
  2. 51
  3. 使用shell函数转化,你可以口算。
  4. 然后执行 jstack -l pid 这里的pid 是进程的pid
  5. 精确查找:jstack -l pid |grep 0x51
  6. "pool-9-thread-4" #69 prio=5 os_prio=0 tid=0x00007efe71a28000 nid=0x51 waiting on condition [0x00007efec7cfb000]
  7. 这里"pool-9-thread-4" 这个线程是比较耗性能。
  8. 说明:本案例整个应用是维护一个线程池,然后不停的消费消息队列中的任务。我这个应用的负载比较小,代码也不存在任何问题,这里处理相对来说是我系统中比较耗CPU的地方。并不代表这里就有问题。

三、 jmap(Memory Map)和 jhat(Java Heap Analysis Tool):

jmap导出堆内存,然后使用jhat来进行分析。jmap用来查看堆内存使用状况,一般结合jhat使用。

语法格式:

  1. jmap [option] <pid> (连接正在执行的进程)
  2. jmap [option] <executable <core> (连接一个core文件)
  3. jmap [option] [server_id@]<remote server IP or hostname> (链接远程服务器)
  4. 如果运行在64JVM上,由于linux操作系统的不同,可能需要指定-J-d64命令选项参数。
  5. [option]:
  6. -heap 打印java heap摘要
  7. -histo[:live] 打印堆中的java对象统计信息
  8. -clstats 打印类加载器统计信息
  9. -finalizerinfo 打印在f-queue中等待执行finalizer方法的对象
  10. -dump:<dump-options> 生成java堆的dump文件
  11. dump-options:
  12. live 只转储存活的对象,如果没有指定则转储所有对象
  13. format=b 二进制格式
  14. file=<file> 转储文件到 <file>
  15. -F 强制选项

示例:
1. 把java堆中的存活对象信息转储到dump.hprof文件

  1. root@dr-6fbc7fd678-t4vdg:/# jmap -dump:live,format=b,file=/home/dump.hprof 6
  2. Dumping heap to /home/dump.hprof ...
  3. Heap dump file created

2. 输出堆的详细信息

  1. root@dr-6fbc7fd678-t4vdg:/# jmap -heap 6
  2. Attaching to process ID 6, please wait...
  3. Debugger attached successfully.
  4. Server compiler detected.
  5. JVM version is 25.111-b14
  6. using thread-local object allocation.
  7. Parallel GC with 8 thread(s)
  8. Heap Configuration:
  9. MinHeapFreeRatio = 0
  10. MaxHeapFreeRatio = 100
  11. MaxHeapSize = 8589934592 (8192.0MB)
  12. NewSize = 2863136768 (2730.5MB)
  13. MaxNewSize = 2863136768 (2730.5MB)
  14. OldSize = 5726797824 (5461.5MB)
  15. NewRatio = 2
  16. SurvivorRatio = 8
  17. MetaspaceSize = 21807104 (20.796875MB)
  18. CompressedClassSpaceSize = 1073741824 (1024.0MB)
  19. MaxMetaspaceSize = 17592186044415 MB
  20. G1HeapRegionSize = 0 (0.0MB)
  21. 整个是堆栈的一些设置。具体意思这里就不在解释。不明白可以参照博客的其他文章,有专门讲解的

3. 输出存活对象统计信息

  1. root@dr-6fbc7fd678-t4vdg:/# jmap -histo:live 6 | more
  2. num #instances #bytes class name
  3. ----------------------------------------------
  4. 1: 40607943 974590632 java.lang.String
  5. 2: 6044125 946298048 [D
  6. 3: 9113 492465352 [I
  7. 4: 8208512 450366536 [C
  8. 5: 18460625 443055000 com.brucexx.dr.txt.dat.DatNeuron
  9. 6: 4844604 232540992 weka.classifiers.trees.RandomTree$Tree
  10. 7: 425202 110350808 [Ljava.lang.Object;
  11. 8: 2421642 58119408 [Lweka.classifiers.trees.RandomTree$Tree;
  12. 9: 130000 40951536 [B
  13. 10: 840946 26910272 java.util.HashMap$Node
  14. 11: 555168 24505416 [Ljava.util.Hashtable$Entry;
  15. 12: 1985 23992072 [Z
  16. 13: 276884 22150720 weka.core.Attribute
  17. 14: 561242 17959744 java.util.Hashtable$Entry
  18. 15: 445573 17822920 java.util.TreeMap$Entry
  19. 16: 276884 15505504 weka.core.ProtectedProperties
  20. 17: 883758 14140128 java.lang.Integer
  21. 18: 278008 13344384 java.util.Hashtable
  22. 19: 418177 10036248 java.util.ArrayList
  23. 20: 20216 8851848 [Ljava.util.HashMap$Node;
  24. 我这里太多了,这里只展示20行,看效果。
  25. class name是对象类型,说明如下:
  26. B byte
  27. C char
  28. D double
  29. F float
  30. I int
  31. J long
  32. Z boolean
  33. [ 数组,如[I表示int[]
  34. [L+类名 其他对象

四、jhat

jhat是用来分析jmap生成dump文件的命令,jhat内置了应用服务器,可以通过网页查看dump文件分析结果,jhat一般是用在离线分析上。

语法格式:

  1. jhat [option] [dumpfile]
  2. option参数解释:
  3. -stack false: 关闭对象分配调用堆栈的跟踪
  4. -refs false: 关闭对象引用的跟踪
  5. -port <port>: HTTP服务器端口,默认是7000
  6. -debug <int>: debug级别
  7. 0: debug输出
  8. 1: Debug hprof file parsing
  9. 2: Debug hprof file parsing, no server
  10. -version 分析报告版本

示例:

  1. jhat dump.hprof

五、jstat

jstat命令是使用频率比较高的命令,主要用来查看JVM运行时的状态信息,包括内存状态、垃圾回收等。.

语法格式:

  1. jstat [option] LVMID [interval] [count]
  2. 其中LVMID是进程idinterval是打印间隔时间(毫秒),count是打印次数(默认一直打印)
  3. option参数解释:
  4. -class class loader的行为统计
  5. -compiler HotSpt JIT编译器行为统计
  6. -gc 垃圾回收堆的行为统计
  7. -gccapacity 各个垃圾回收代容量(young,old,perm)和他们相应的空间统计
  8. -gcutil 垃圾回收统计概述
  9. -gccause 垃圾收集统计概述(同-gcutil),附加最近两次垃圾回收事件的原因
  10. -gcnew 新生代行为统计
  11. -gcnewcapacity 新生代与其相应的内存空间的统计
  12. -gcold 年老代和永生代行为统计
  13. -gcoldcapacity 年老代行为统计
  14. -gcpermcapacity 永生代行为统计
  15. -printcompilation HotSpot编译方法统计

示例:
pid为6,每隔1000毫秒打印一次,打印4次

  1. jstat -gc 6 1000 4
  2. root@dr-6fbc7fd678-t4vdg:/usr/lib/jvm/java-8-openjdk-amd64/bin# jstat -gc 6 1000 4
  3. S0C S1C S0U S1U EC EU OC OU MC MU CCSC CCSU YGC YGCT FGC FGCT GCT
  4. 12800.0 12288.0 6790.6 0.0 2770944.0 314589.3 5592576.0 3938355.6 102976.0 98690.0 10624.0 9660.2 2614 58.562 6 18.197 76.759
  5. 12800.0 12288.0 6790.6 0.0 2770944.0 315367.7 5592576.0 3938355.6 102976.0 98690.0 10624.0 9660.2 2614 58.562 6 18.197 76.759
  6. 12800.0 12288.0 6790.6 0.0 2770944.0 316227.1 5592576.0 3938355.6 102976.0 98690.0 10624.0 9660.2 2614 58.562 6 18.197 76.759
  7. 12800.0 12288.0 6790.6 0.0 2770944.0 317143.2 5592576.0 3938355.6 102976.0 98690.0 10624.0 9660.2 2614 58.562 6 18.197 76.759
  8. 字段解释:
  9. S0C survivor0大小
  10. S1C survivor1大小
  11. S0U survivor0已使用大小
  12. S1U survivor1已使用大小
  13. EC Eden区大小
  14. EU Eden区已使用大小
  15. OC 老年代大小
  16. OU 老年代已使用大小
  17. MC 方法区大小
  18. MU 方法区已使用大小
  19. CCSC 压缩类空间大小
  20. CCSU 压缩类空间已使用大小
  21. YGC 年轻代垃圾回收次数
  22. YGCT 年轻代垃圾回收消耗时间
  23. FGC 老年代垃圾回收次数
  24. FGCT 老年代垃圾回收消耗时间
  25. GCT 垃圾回收消耗总时间
  26. jstat -gcutil 6 1000 4
  27. root@dr-6fbc7fd678-t4vdg:/usr/lib/jvm/java-8-openjdk-amd64/bin# jstat -gcutil 6 1000 4
  28. S0 S1 E O M CCS YGC YGCT FGC FGCT GCT
  29. 53.05 0.00 12.21 70.42 95.84 90.93 2614 58.562 6 18.197 76.759
  30. 53.05 0.00 12.24 70.42 95.84 90.93 2614 58.562 6 18.197 76.759
  31. 53.05 0.00 12.28 70.42 95.84 90.93 2614 58.562 6 18.197 76.759
  32. 53.05 0.00 12.30 70.42 95.84 90.93 2614 58.562 6 18.197 76.759
  33. 字段解释:
  34. S0 survivor0使用百分比
  35. S1 survivor1使用百分比
  36. E Eden区使用百分比
  37. O 老年代使用百分比
  38. M 元数据区使用百分比
  39. CCS 压缩使用百分比
  40. YGC 年轻代垃圾回收次数
  41. YGCT 年轻代垃圾回收消耗时间
  42. FGC 老年代垃圾回收次数
  43. FGCT 老年代垃圾回收消耗时间
  44. GCT 垃圾回收消耗总时间
  45. 分析一下:
  46. Minor GC=58.562/2614 = 20ms
  47. Full GC=18.197/6 = 3ms
  48. 次要GC一共执行2614次,耗时:58.562,差不多每个20ms,属于回收比较快的,没啥问题;
  49. Full GC一共执行了6次,说明执行的次数并不是很多,内存比较充足。 但是full GC的时间为3s,执行时间比较长,说明内存设置比较大的原因。
  50. 优化参数显示:
  51. 内存比较充足,如果你服务器资源比较少,可以减少内存大小;
  52. 3天执行了6full gcfull GC的频率比较低。每次full gc比较长,说明一次full gc的时候,处理的内容比较多。如果服务器资源比较少,可以适当的减少内存分配; 另外回收策略可以进一步优化。

五、hprof(Heap/CPU Profiling Tool):

hprof能够展现CPU使用率,统计堆内存使用情况。
HPROF: 一个Heap/CPU Profiling工具:J2SE中提供了一个简单的命令行工具来对java程序的cpu和heap进行 profiling,叫做HPROF。HPROF实际上是JVM中的一个native的库,它会在JVM启动的时候通过命令行参数来动态加载,并成为 JVM进程的一部分。若要在java进程启动的时候使用HPROF,用户可以通过各种命令行参数类型来使用HPROF对java进程的heap或者 (和)cpu进行profiling的功能。HPROF产生的profiling数据可以是二进制的,也可以是文本格式的。这些日志可以用来跟踪和分析 java进程的性能问题和瓶颈,解决内存使用上不优的地方或者程序实现上的不优之处。二进制格式的日志还可以被JVM中的HAT工具来进行浏览和分析,用 以观察java进程的heap中各种类型和数据的情况。在J2SE 5.0以后的版本中,HPROF已经被并入到一个叫做Java Virtual Machine Tool Interface(JVM TI)中。

请参照:https://www.jianshu.com/p/6cf70a7e82cb

发表评论

表情:
评论列表 (有 0 条评论,182人围观)

还没有评论,来说两句吧...

相关阅读

    相关 JVM-JVM性能

    JVM性能调优的目标和方法 JVM性能调优的目标是使JVM在运行Java应用程序时能够更加高效地利用计算机的资源,以提高应用程序的性能和响应能力。具体来说,JVM性能调优

    相关 JVM性能工具

    一、JDK工具 先来看看有哪些常用的工具可以辅助我们进行性能调优和问题排查,后面再通过一个具体的示例结合工具来分析调优。 1、JDK工具 JDK自带了很多性能监控