Java-JVM命令调优(基础)

注意: 以下教程是在 JDK<=JDK8 能使用 而JDK9有变动

top介绍

top命令是Linux下常用的性能分析工具,能够实时显示系统中各个进程的资源占用状况,类似于Windows的任务管理器

下面就简单说下我们需要知道的内容:

java nonheap调优 java 调优命令_java虚拟机

更多详细上百度找

如果top命令查看cpu利用率超过100%
通过在top的情况下按大键盘的1,查看cpu的核数
top命令显示的是你的程序占用的cpu的总数,也就是说如果你是4核cpu那么cpu最高占用率可达400%,top里显示的是把所有使用率加起来。
查看一下CPU信息:在命令行里输入:cat /proc/cpuinfo -> cpu cores 就是你得cpu核数

查询进程

通过top查询列出一大堆不太好找,我们可以通过ps -ef | grep 名称 来查找

java nonheap调优 java 调优命令_jvm_02


如果进程死了那么就查询不到了

jstack介绍

jstack常用来打印Java进程/core文件/远程调试端口的Java线程堆栈跟踪信息,包含当前虚拟机中所有线程正在执行的方法堆栈信息的集合。

主要用来定位线程出现长时间停顿的原因,如线程间死锁、死循环、请求外部资源导致的长时间等待。

使用jstack前提必须Linux装有java,而且配置好环境变量了否则不能使用

jstack用法很多这里就不在一 一的介绍了自己上百度查找

输出格式

jstack的输出是该进程下的所有线程的堆栈集合,下面是一个线程的堆栈快照信息:

"pool-1-thread-3" #12 prio=5 os_prio=0 tid=0x00007fc99412f000 nid=0x9bc in Object.wait() [0x00007fc97c2f2000]
    java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
     - waiting on <0x00000000d7017420> (a com.liang.java.thinkinginjava.concurency.waxomatic.Car)
      at java.lang.Object.wait(Object.java:502)
      at com.liang.java.thinkinginjava.concurency.waxomatic.Car.waitForBuffing(WaxOMatic.java:47)
      - locked <0x00000000d7017420> (a com.liang.java.thinkinginjava.concurency.waxomatic.Car)
      at com.liang.java.thinkinginjava.concurency.waxomatic.WaxOn.run(WaxOMatic.java:61)
      at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
     at java.lang.Thread.run(Thread.java:745)
    Locked ownable synchronizers:
    - <0x00000000d729cdb0> (a java.util.concurrent.ThreadPoolExecutor$Worker)

其中 “pool-1-thread-3” 是线程名称

prio=5 是该线程JVM中的优先级

os_prio=0 是该线程在OS中的优先级

tid=0x00007fc99412f000 是JVM内的thread id (Java-level thread ID)

nid=0x9bc 是Native thread ID,本地操作系统相关的线程id

线程状态

在jstack输出的第二行为线程的状态,在JVM中线程状态使用枚举 java.lang.Thread.State 来表示,State的定义如下:

这个状态是指的JVM中的状态,与任何操作系统的线程状态都没有任何关系。

其中RUNNABLE表示:线程在JVM中是可以执行的了,但是他可能还在等待着某些操作系统资源,如:cpu

其中BLOCKED表示:表示线程在等待或被notify后等待重新进入synchronized代码块/方法

其中WAITING表示:表示调用了Object.wait()/Thread.join()/LockSupport.park()方法,等待被另一个线程唤醒。例如一个线程调用了Object.wait(),在等待另一个线程调用Object.notify()/Object.notifyAll();一个线程调用了Thread.join(),在等待另一线程到达terinate状态

其中TIMED_WAITING表示:表示线程调用了Object.sleep(long)/Object.wait(long)/Thread.join(long)/LockSupport.parkNanos()/LockSupport.parkUntil()等,等待一段时间后就会自动结束的方法;

也就是说BLOCKED在等待锁,WAITING在等待被其他线程,TIMED_WAITING是带闹钟的WAITING

top+jstack(定位耗时最长的代码)

  1. top 查询占用cpu的进程,最多耗时的java进程 找到后ctrl+c退出
    列:
top

java nonheap调优 java 调优命令_java虚拟机_03

  1. top -H -p 进程的pid号 查询指定进程的线程(最耗cpu的)
    列:
top -H -p 20669

java nonheap调优 java 调优命令_虚拟机_04

如果不确定程序到底是不是我们想要看的java程序那么我们可以先使用下面命令找到对应的java程序后和top的进程pid进行对比就行了

ps -ef|grep java  #查询所有java进程
[root@VM-8-12-centos ~]# ps -ef|grep java
root      2072     1  0 4月12 ?       1-02:28:14 java -jar interview-eureka-1.0-SNAPSHOT.jar
root      7778 31135  0 23:04 pts/0    00:00:00 grep --color=auto java
root      8956     1  0 6月10 ?       00:00:00 sudo -u springboot nohup /usr/bin/java -jar /data/java/fastdfs/FastDFS-1.0-SNAPSHOT.jar --server.port=20210
springb+  8960  8956  0 6月10 ?       01:30:44 /usr/bin/java -jar /data/java/fastdfs/FastDFS-1.0-SNAPSHOT.jar --server.port=20210
root     12369     1  0 7月23 ?       00:38:21 java -jar interview-web-1.0-SNAPSHOT.jar
root     20669     1  0 4月12 ?       20:12:09 java -jar interview-feign-1.0-SNAPSHOT.jar
  1. printf “%x\n” 线程的pid号 ,将线程号转换为16进制
    列:
[root@VM-8-12-centos ~]# printf "%x\n"  21640
5488
  1. jstack 进程PID | grep 转换线程号后的16进制 打印具体问题/或者情况
    列:
jstack 20669 | grep 5488
[root@VM-8-12-centos ~]# jstack 20669 | grep 5488  
"RxComputationScheduler-1" #41 daemon prio=5 os_prio=0 tid=0x00007fb081079800 nid=0x5488 waiting on condition [0x00007fb0471f2000]
  1. jstack 进程PID 打印具体堆栈,可追踪到代码具体位置
    列:
jstack 20669
"Reference Handler" #2 daemon prio=10 os_prio=0 tid=0x00007fb08009b800 nid=0x50c0 in Object.wait() [0x00007fb070c5f000]
   java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        at java.lang.Object.wait(Object.java:502)
        at java.lang.ref.Reference.tryHandlePending(Reference.java:191)
        - locked <0x00000000ecdbeae8> (a java.lang.ref.Reference$Lock)
        at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153)

"VM Thread" os_prio=0 tid=0x00007fb080094000 nid=0x50bf runnable 

"VM Periodic Task Thread" os_prio=0 tid=0x00007fb0800dd000 nid=0x50d1 waiting on condition 

JNI global references: 1480

查看线程关系

pstree -p 线程pid号 查看进程中线程的关系

查询堆栈

显示java堆详细信息 ,比如堆的配置,和使用情况…

堆详细信息

命令:jmap -heap pid

描述:显示Java堆详细信息 ,打印堆的摘要信息,包括使用的GC算法、堆配置信息和各内存区域内存使用信息

列:

[root@bogon ~]# jmap -heap  56832
Attaching to process ID 56832, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.40-b25

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

Heap Configuration:
   MinHeapFreeRatio         = 0
   MaxHeapFreeRatio         = 100
   MaxHeapSize              = 478150656 (456.0MB)
   NewSize                  = 10485760 (10.0MB)
   MaxNewSize               = 159383552 (152.0MB)
   OldSize                  = 20971520 (20.0MB)
   NewRatio                 = 2
   SurvivorRatio            = 8
   MetaspaceSize            = 21807104 (20.796875MB)
   CompressedClassSpaceSize = 1073741824 (1024.0MB)
   MaxMetaspaceSize         = 17592186044415 MB
   G1HeapRegionSize         = 0 (0.0MB)

Heap Usage:
PS Young Generation
Eden Space:
   capacity = 8388608 (8.0MB)
   used     = 1870440 (1.7837905883789062MB)
   free     = 6518168 (6.216209411621094MB)
   22.297382354736328% used
From Space:
   capacity = 1048576 (1.0MB)
   used     = 0 (0.0MB)
   free     = 1048576 (1.0MB)
   0.0% used
To Space:
   capacity = 1048576 (1.0MB)
   used     = 0 (0.0MB)
   free     = 1048576 (1.0MB)
   0.0% used
PS Old Generation
   capacity = 20971520 (20.0MB)
   used     = 0 (0.0MB)
   free     = 20971520 (20.0MB)
   0.0% used

1711 interned Strings occupying 109808 bytes.
[root@bogon ~]# jmap -heap  56832
Attaching to process ID 56832, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.40-b25

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

Heap Configuration:
   MinHeapFreeRatio         = 0
   MaxHeapFreeRatio         = 100
   MaxHeapSize              = 478150656 (456.0MB)
   NewSize                  = 10485760 (10.0MB)
   MaxNewSize               = 159383552 (152.0MB)
   OldSize                  = 20971520 (20.0MB)
   NewRatio                 = 2
   SurvivorRatio            = 8
   MetaspaceSize            = 21807104 (20.796875MB)
   CompressedClassSpaceSize = 1073741824 (1024.0MB)
   MaxMetaspaceSize         = 17592186044415 MB
   G1HeapRegionSize         = 0 (0.0MB)

Heap Usage:
PS Young Generation
Eden Space:
   capacity = 8388608 (8.0MB)
   used     = 1870440 (1.7837905883789062MB)
   free     = 6518168 (6.216209411621094MB)
   22.297382354736328% used
From Space:
   capacity = 1048576 (1.0MB)
   used     = 0 (0.0MB)
   free     = 1048576 (1.0MB)
   0.0% used
To Space:
   capacity = 1048576 (1.0MB)
   used     = 0 (0.0MB)
   free     = 1048576 (1.0MB)
   0.0% used
PS Old Generation
   capacity = 20971520 (20.0MB)
   used     = 0 (0.0MB)
   free     = 20971520 (20.0MB)
   0.0% used

1711 interned Strings occupying 109808 bytes.

Heap Configuration 是JVM的配置

几个重点需要知道的:

  1. MaxHeapSize jvm最大堆内存(Eden +from+to+old)
  2. NewSize 新生代堆空间的默认值
  3. MaxNewSize 新生代堆空间的最大值
  4. NewRatio ( 新生代(2个Survivor区和Eden区 )与老年代(不包括永久区)的堆空间比值,表示新生代:老年代=1:2。)
  5. SurvivorRatio (新生代和Eden的比例比如: 8 (Eden): 1(新生代) 我们有两个新生代所以是8:2)
  6. G1HeapRegionSize 在使用 G1 垃圾回收算法时,JVM 会将 Heap 空间分隔为若干个 Region,该参数用来指定每个 Region 空间的大小。

Heap Usage 是JVM使用情况

Eden   Space是 : 伊甸园

From  Space  新生代(1)区

to        Space  新生代(2)区

PS Old Generation 老年代使用情况

其他参数解析:

capacity 是总数值

used 是使用空间

free 空闲空间

0.0% used是使用空间占比

查询堆类使用情况

命令:jmap -histo:live pid

描述:显示堆中对象的统计信息

中包括每个Java类、对象数量、内存大小(单位:字节)、完全限定的类名。

打印的虚拟机内部的类名称将会带有一个’*’前缀。如果指定了live子选项,则只计算活动的对象。

jmap -histo:live pid

列:

[root@bogon ~]# jmap -histo:live 56832

 num     #instances         #bytes  class name
----------------------------------------------
   1:          2958         169792  [C
   2:           430         146104  [B
   3:           650          73856  java.lang.Class
   4:          2935          70440  java.lang.String
   5:           589          35552  [Ljava.lang.Object;
   6:           550          17600  java.util.HashMap$Node
   7:           133          11336  [I
   8:           122           6480  [Ljava.lang.String;
   9:            22           5984  [Ljava.util.HashMap$Node;
  10:           111           4440  java.lang.ref.SoftReference
  11:           256           4096  java.lang.Integer
  12:           127           4064  java.util.concurrent.ConcurrentHashMap$Node
  13:           109           3488  java.util.Hashtable$Entry
  14:             7           2632  java.lang.Thread
  15:            18           2208  [Ljava.util.concurrent.ConcurrentHashMap$Node;
  16:            43           2064  sun.util.locale.LocaleObjectCache$CacheEntry
  17:            31           1984  java.net.URL
  18:            24           1920  java.lang.reflect.Constructor
  19:             1           1560  [[B
  ..................................................................

类加载器信息

命令:jmap -clstats pid
描述:打印类加载器信息

-clstats是-permstat的替代方案,在JDK8之前,-permstat用来打印类加载器的数据
打印Java堆内存的永久保存区域的类加载器的智能统计信息。对于每个类加载器而言,它的名称、活跃度、地址、父类加载器、它所加载的类的数量和大小都会被打印。此外,包含的字符串数量和大小也会被打印。

列:

[root@bogon ~]# jmap -clstats 56832
Attaching to process ID 56832, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.40-b25
finding class loader instances ..done.
computing per loader stat ..done.
please wait.. computing liveness..............................done.
class_loader    classes bytes   parent_loader   alive?  type

<bootstrap>     564     1046296   null          live    <internal>
0x00000000e3801638      17      52957   0x00000000e3801698      live    sun/misc/Launcher$AppClassLoader@0x000000010000f038
0x00000000e3801698      7       14882     null          live    sun/misc/Launcher$ExtClassLoader@0x000000010000f3d0
0x00000000e3884720      0       0       0x00000000e3801638      live    java/util/ResourceBundle$RBClassLoader@0x0000000100054080

total = 4       588     1114135     N/A         alive=4, dead=0     N/A

等待终结的对象信息

命令:jmap -finalizerinfo pid
描述:打印等待终结的对象信息

列:

[root@bogon ~]# jmap -finalizerinfo 56832
Attaching to process ID 56832, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.40-b25
Number of objects pending for finalization: 0

Number of objects pending for finalization: 0 说明当前F-QUEUE队列中并没有等待Fializer线程执行final

堆转储快照dump文件

命令:jmap -dump:format=b,file=./heapdump.phrof pid
描述:生成堆转储快照dump文件。

以hprof二进制格式转储Java堆到指定filename的文件中。live子选项是可选的。如果指定了live子选项,堆中只有活动的对象会被转储。想要浏览heap dump,你可以使用jhat(Java堆分析工具)读取生成的文件。

这个命令执行,JVM会将整个heap的信息dump写入到一个文件,heap如果比较大的话,就会导致这个过程比较耗时,并且执行的过程中为了保证dump的信息是可靠的,所以会暂停应用, 线上系统慎用。

[root@bogon ~]# jmap -dump:format=b,file=./heapdump.phrof  56832
Dumping heap to /root/heapdump.phrof ...
Heap dump file created

然后我们可以把 /root/heapdump.phrof 下载下来

在windows 中使用JProfiler 打开phrof 文件 或者JDK8->bin 目录下 jvisualvm 工具 打开phrof 文件

注意:如果使用的是JProfiler 那么我们生成的文件后缀要换了

jmap -dump:format=b,file=heapdump.hprof 56832

jmap -dump:format=b,file=heapdump.jps  56832

查询gc次数

语法: jstat -gc pid

列:

[hd@oaapp2 ~]$ jstat -gc 13547  
 S0C    S1C    S0U    S1U      EC       EU        OC         OU       MC     MU    CCSC   CCSU   YGC     YGCT    FGC    FGCT     GCT   
1024.0 512.0   0.0   160.0  2729472.0 1828661.6 2054144.0   996630.7  419828.0 354747.5 54528.0 38470.2  93431 1946.883  29     22.794 1969.678

S0C:第一个幸存区的大小
S1C:第二个幸存区的大小
S0U:第一个幸存区的使用大小
S1U:第二个幸存区的使用大小
EC:伊甸园区的大小
EU:伊甸园区的使用大小
OC:老年代大小
OU:老年代使用大小
MC:方法区大小
MU:方法区使用大小
CCSC:压缩类空间大小
CCSU:压缩类空间使用大小
YGC:年轻代垃圾回收次数
YGCT:年轻代垃圾回收消耗时间
FGC:老年代垃圾回收次数
FGCT:老年代垃圾回收消耗时间
GCT:垃圾回收消耗总时间

定时统计

jstat -gc 13547   10000  30

java程序突然挂掉的原因

dmesg只能监控当天的 并且是内存溢出的问题 ,如果不是那么就不会显示

dmesg -T | grep "(java)" 

dmesg -T | grep "(java)" > dmesg.txt

如果出现类似

memory: Kill process 20982 (java) score 847 or sacrifice child 代表内存满了,把java程序杀死了