1. 程式人生 > >JVM調優的liunx命令

JVM調優的liunx命令

在平時的運維工作中,我們經常會碰到下面這些問題:

1、OutOfMemoryError,記憶體不足
2、記憶體洩露
3、執行緒死鎖
4、鎖爭用(Lock Contention)
5、Java程序消耗CPU過高

導致伺服器CPU或者記憶體飆高影響線上業務,對於解決以上問題,我們常用的JVM效能調優監控工具有:jps、jstat、jstack、jmap、jhat、hprof、jinfo

如果想要檢視Java程序中執行緒堆疊的資訊,可以選擇jstack,如果要檢視堆記憶體,可以使用jmap匯出並使用jhat來進行分析,包括檢視類的載入資訊,GC演算法那,物件的使用情況等,還可以使用jstat來對JVM進行統計監測,包括檢視各個區記憶體和GC的情況,還可以使用hprof能夠展現CPU使用率,統計堆記憶體使用情況。

1、jps命令:

作用:

主要用來輸出JVM中執行的程序狀態資訊。語法格式如下:

語法格式:

jps [options] [hostid] 
如果不指定hostid就預設為當前主機或伺服器。

命令引數:

-q 不輸出類名、Jar名和傳入main方法的引數
-m 輸出傳入main方法的引數
-l 輸出main類或Jar的全限名
-v 輸出傳入JVM的引數
[[email protected] ~]# jps -lm
Picked up _JAVA_OPTIONS: -Dawt.useSystemAAFontSettings=lcd
9346 org.apache.catalina
.startup.Bootstrap start 19301 GpsTracker4.jar 12520 org.apache.catalina.startup.Bootstrap start 25402 GPSTracker1.jar 18463 GPSTracker5.jar 7940 org.apache.catalina.startup.Bootstrap start 12452 org.apache.catalina.startup.Bootstrap start 8865 org.apache.catalina.startup.Bootstrap start 5489 org.apache
.catalina.startup.Bootstrap start 1568 org.apache.catalina.startup.Bootstrap start 32543 GPSTracker2.jar 25441 org.apache.catalina.startup.Bootstrap start 574 org.apache.catalina.startup.Bootstrap start 14498 org.apache.catalina.startup.Bootstrap start 25453 ./DEyesPushServer.jar 2723 org.apache.catalina.startup.Bootstrap start 10584 bdwiseGpsTrack.jar 2031 org.apache.catalina.startup.Bootstrap start

加入引數-V後,會把jvm的啟動引數全部輸出:

[[email protected] ~]# jps -lmv
Picked up _JAVA_OPTIONS: -Dawt.useSystemAAFontSettings=lcd
9346 org.apache.catalina.startup.Bootstrap start -Djava.util.logging.config.file=/home/tomcat/tomcat6/9704_event/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Xms256m -Xmx3072m -XX:PermSize=256M -XX:MaxPermSize=768M -Djava.endorsed.dirs=/home/tomcat/tomcat6/9704_event/endorsed -Dcatalina.base=/home/tomcat/tomcat6/9704_event -Dcatalina.home=/home/tomcat/tomcat6/9704_event -Djava.io.tmpdir=/home/tomcat/tomcat6/9704_event/temp -Dawt.useSystemAAFontSettings=lcd
19301 GpsTracker4.jar -Dawt.useSystemAAFontSettings=lcd
12520 org.apache.catalina.startup.Bootstrap start -Djava.util.logging.config.file=/home/tomcat/tomcat_gps_prod/9301_gpstrack/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Xms256m -Xmx3072m -XX:PermSize=256M -XX:MaxPermSize=768M -Djava.endorsed.dirs=/home/tomcat/tomcat_gps_prod/9301_gpstrack/endorsed -Dcatalina.base=/home/tomcat/tomcat_gps_prod/9301_gpstrack -Dcatalina.home=/home/tomcat/tomcat_gps_prod/9301_gpstrack -Djava.io.tmpdir=/home/tomcat/tomcat_gps_prod/9301_gpstrack/temp -Dawt.useSystemAAFontSettings=lcd
25402 GPSTracker1.jar -Dawt.useSystemAAFontSettings=lcd
18463 GPSTracker5.jar -Dawt.useSystemAAFontSettings=lcd

2.jstat命令

作用:

用於監視虛擬機器執行時狀態資訊的命令,它可以顯示出虛擬機器程序中的類裝載、記憶體、垃圾收集、JIT編譯等執行資料

語法格式:

jstat [option] LVMID [interval] [count]

引數含義:

[option] : 操作引數
LVMID   : Java虛擬機器ID,在Linux/Unix系統上一般就是程序ID
[interval] : 是取樣時間間隔
[count] : count是取樣數目

option引數總覽:
這裡寫圖片描述

option 引數詳解

-class:監視類裝載、解除安裝數量、總空間以及耗費的時間

[root@web02 ~]# jstat -class 9346
Picked up _JAVA_OPTIONS: -Dawt.useSystemAAFontSettings=lcd
Loaded  Bytes  Unloaded  Bytes     Time   
 31909 64439.1      998  2028.2      22.75
[root@web02 ~]# jstat -class 12520
Picked up _JAVA_OPTIONS: -Dawt.useSystemAAFontSettings=lcd
Loaded  Bytes  Unloaded  Bytes     Time   
  7696 15390.2        0     0.0       8.84
[root@web02 ~]# jstat -class 7940
Picked up _JAVA_OPTIONS: -Dawt.useSystemAAFontSettings=lcd
Loaded  Bytes  Unloaded  Bytes     Time   
 27776 54941.7      136   292.5      27.44
Loaded : 載入class的數量
Bytes : class位元組大小
Unloaded : 未載入class的數量
Bytes : 未載入class的位元組大小
Time : 載入時間

-compiler:輸出JIT編譯過的方法數量耗時等

[root@web02 ~]# jstat -compiler 9346
Picked up _JAVA_OPTIONS: -Dawt.useSystemAAFontSettings=lcd
Compiled Failed Invalid   Time   FailedType FailedMethod
    6262      5       0   137.64          1 org/springframework/context/annotation/CommonAnnotationBeanPostProcessor buildResourceMetadata
[root@web02 ~]# jstat -compiler 12520
Picked up _JAVA_OPTIONS: -Dawt.useSystemAAFontSettings=lcd
Compiled Failed Invalid   Time   FailedType FailedMethod
    1013      3       0    18.29          1 org/apache/catalina/loader/WebappClassLoader findResourceInternal
[root@web02 ~]# jstat -compiler 7940
Picked up _JAVA_OPTIONS: -Dawt.useSystemAAFontSettings=lcd
Compiled Failed Invalid   Time   FailedType FailedMethod
    4163      2       0    84.02          1 org/apache/catalina/loader/WebappClassLoader findResourceInternal
[root@web02 ~]# ps -ef | grep 7940
root      5665  4118  0 17:29 pts/11   00:00:00 grep 7940

Compiled : 編譯數量
Failed : 編譯失敗數量
Invalid : 無效數量
Time : 編譯耗時
FailedType : 失敗型別
FailedMethod : 失敗方法的全限定名
-gc:垃圾回收堆的行為統計,常用命令

[root@web02 ~]# jstat -gc 9346
Picked up _JAVA_OPTIONS: -Dawt.useSystemAAFontSettings=lcd
 S0C    S1C    S0U    S1U      EC       EU        OC         OU       PC     PU    YGC     YGCT    FGC    FGCT     GCT   
20992.0 32256.0 4952.4  0.0   227840.0 147675.8  222720.0   167726.6  262144.0 188115.3     46    1.324   5      2.933    4.256

比如下面輸出的是GC資訊,取樣時間間隔為250ms,取樣數為4:

[root@web02 ~]# jstat -gc 9346 250 4
Picked up _JAVA_OPTIONS: -Dawt.useSystemAAFontSettings=lcd
 S0C    S1C    S0U    S1U      EC       EU        OC         OU       PC     PU    YGC     YGCT    FGC    FGCT     GCT   
20992.0 32256.0 4952.4  0.0   227840.0 147678.0  222720.0   167726.6  262144.0 188118.3     46    1.324   5      2.933    4.256
20992.0 32256.0 4952.4  0.0   227840.0 147678.0  222720.0   167726.6  262144.0 188118.3     46    1.324   5      2.933    4.256
20992.0 32256.0 4952.4  0.0   227840.0 147678.0  222720.0   167726.6  262144.0 188118.3     46    1.324   5      2.933    4.256
20992.0 32256.0 4952.4  0.0   227840.0 147678.0  222720.0   167726.6  262144.0 188118.3     46    1.324   5      2.933    4.256

要明白上面各列的意義,先看JVM堆記憶體佈局:
這裡寫圖片描述

可以看出:

堆記憶體 = 年輕代 + 年老代 + 永久代
年輕代 = Eden區 + 兩個Survivor區(From和To)

現在來解釋各列含義:

C即Capacity 總容量,U即Used 已使用的容量

S0C : survivor0區的總容量
S1C : survivor1區的總容量
S0U : survivor0區已使用的容量
S1C : survivor1區已使用的容量
EC : Eden區的總容量
EU : Eden區已使用的容量
OC : Old區的總容量
OU : Old區已使用的容量
PC 當前perm的容量 (KB)
PU perm的使用 (KB)
YGC : 新生代垃圾回收次數
YGCT : 新生代垃圾回收時間
FGC : 老年代垃圾回收次數
FGCT : 老年代垃圾回收時間
GCT : GC垃圾回收總消耗時間

-gcutil:同-gc,不過輸出的是已使用空間佔總空間的百分比

[root@web02 etc]# jstat -gcutil 29544
  S0     S1     E      O      P     YGC     YGCT    FGC    FGCT     GCT   
 62.67   0.00  65.20  16.10  99.85     34    1.235     0    0.000    1.235

-gccause:垃圾收集統計概述(同-gcutil),附加最近兩次垃圾回收事件的原因

[root@web02 etc]# jstat -gccause 29544
  S0     S1     E      O      P     YGC     YGCT    FGC    FGCT     GCT    LGCC                 GCC                 
 62.67   0.00  65.20  16.10  99.85     34    1.235     0    0.000    1.235 Allocation Failure   No GC 

LGCC:最近垃圾回收的原因
GCC:當前垃圾回收的原因
-gcnew:統計新生代的行為

[root@web02 etc]# jstat -gcnew 29544
 S0C    S1C    S0U    S1U   TT MTT  DSS      EC       EU     YGC     YGCT  
34944.0 34944.0 21900.2    0.0 16  31 17472.0 279616.0 182323.5     34    1.235

TT:Tenuring threshold(提升閾值)
MTT:最大的tenuring threshold
DSS:survivor區域大小 (KB)
-gcnewcapacity:新生代與其相應的記憶體空間的統計

Picked up _JAVA_OPTIONS: -Dawt.useSystemAAFontSettings=lcd
  NGCMN      NGCMX       NGC      S0CMX     S0C     S1CMX     S1C       ECMX        EC      YGC   FGC 
  349504.0   349504.0   349504.0  34944.0  34944.0  34944.0  34944.0   279616.0   279616.0    34     0

NGC:當前年輕代的容量 (KB)
S0CMX:最大的S0空間 (KB)
S0C:當前S0空間 (KB)
ECMX:最大eden空間 (KB)
EC:當前eden空間 (KB)

-gcold:統計舊生代的行為

[root@web02 etc]# jstat -gclod 29544
   PC       PU        OC          OU       YGC    FGC    FGCT     GCT   
164480.0 164236.6    699072.0    112581.0     34     0    0.000    1.235

-gcoldcapacity:統計舊生代的大小和空間

[root@web02 etc]# jstat -gcoldcapacity 29544
   OGCMN       OGCMX        OGC         OC       YGC   FGC    FGCT     GCT   
   699072.0    699072.0    699072.0    699072.0    34     0    0.000    1.235

-gcpermcapacity:永生代行為統計

[root@web02 etc]# jstat -gcpermcapacity 29544
  PGCMN      PGCMX       PGC         PC      YGC   FGC    FGCT     GCT   
  131072.0   262144.0   164480.0   164480.0    34     0    0.000    1.235

-printcompilation:hotspot編譯方法統計

[[email protected] etc]# jstat -printcompilation 29544
Compiled  Size  Type Method
    2957   1032    1 org/apache/jasper/compiler/SmapUtil$SDEInstaller copyConstantPool

Compiled:被執行的編譯任務的數量
Size:方法位元組碼的位元組數
Type:編譯型別
Method:編譯方法的類名和方法名。類名使用”/” 代替 “.” 作為空間分隔符. 方法名是給出類的方法名. 格式是一致於HotSpot – XX:+PrintComplation 選項

jmap命令:
作用:

jmap(JVM Memory Map)命令用來檢視堆記憶體使用狀況,一般結合jhat使用,用於生成heap dump檔案,如果不使用這個命令,還可以使用-XX:+HeapDumpOnOutOfMemoryError引數來讓虛擬機器出現OOM的時候·自動生成dump檔案。jmap不僅能生成dump檔案,還可以查詢finalize執行佇列、Java堆和永久代的詳細資訊,如當前使用率、當前使用的是哪種收集器等。

命令格式:

jmap [option] LVMID

option引數:

dump : 匯出記憶體轉儲快照
finalizerinfo : 顯示在F-Queue佇列等待Finalizer執行緒執行finalizer方法的物件
heap : 顯示Java堆詳細資訊
histo : 顯示堆中物件的統計資訊
permstat : to print permanent generation statistics
F : 當-dump沒有響應時,強制生成dump快照

-permstat:列印程序的類載入器和類載入器載入的持久代物件資訊,輸出:類載入器名稱、物件是否存活(不可靠)、物件地址、父類載入器、已載入的類大小等資訊

$ jmap -permstat 28920
  Attaching to process ID 28920, please wait...
  Debugger attached successfully.
  Server compiler detected.
  JVM version is 24.71-b01
  finding class loader instances ..done.
  computing per loader stat ..done.
  please wait.. computing liveness.liveness analysis may be inaccurate ...

  class_loader            classes bytes   parent_loader           alive?  type  
  <bootstrap>             3111    18154296          null          live    <internal>
  0x0000000600905cf8      1       1888    0x0000000600087f08      dead    sun/reflect/[email protected]0x00000007800500a0
  0x00000006008fcb48      1       1888    0x0000000600087f08      dead    sun/reflect/[email protected]0x00000007800500a0
  0x00000006016db798      0       0       0x00000006008d3fc0      dead    java/util/[email protected]0x0000000780626ec0
  0x00000006008d6810      1       3056      null          dead    sun/reflect/[email protected]0x00000007800500a0

-heap:檢視程序堆記憶體使用情況,包括使用的GC演算法、堆配置引數和各代中堆記憶體使用情況,可以用此來判斷記憶體目前的使用情況以及垃圾回收情況

[[email protected] etc]# jmap -heap 29544
Attaching to process ID 29544, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 24.71-b01

using parallel threads in the new generation.
using thread-local object allocation.
Concurrent Mark-Sweep GC

Heap Configuration:
   MinHeapFreeRatio = 40
   MaxHeapFreeRatio = 70
   MaxHeapSize      = 1073741824 (1024.0MB)
   NewSize          = 357892096 (341.3125MB)
   MaxNewSize       = 357892096 (341.3125MB)
   OldSize          = 715784192 (682.625MB)
   NewRatio         = 2
   SurvivorRatio    = 8
   PermSize         = 134217728 (128.0MB)
   MaxPermSize      = 268435456 (256.0MB)
   G1HeapRegionSize = 0 (0.0MB)

Heap Usage:
New Generation (Eden + 1 Survivor Space):
   capacity = 322109440 (307.1875MB)
   used     = 231861032 (221.11991119384766MB)
   free     = 90248408 (86.06758880615234MB)
   71.98206671620676% used
Eden Space:
   capacity = 286326784 (273.0625MB)
   used     = 209435192 (199.73296356201172MB)
   free     = 76891592 (73.32953643798828MB)
   73.14551194763533% used
From Space:
   capacity = 35782656 (34.125MB)
   used     = 22425840 (21.386947631835938MB)
   free     = 13356816 (12.738052368164062MB)
   62.672374012706044% used
To Space:
   capacity = 35782656 (34.125MB)
   used     = 0 (0.0MB)
   free     = 35782656 (34.125MB)
   0.0% used
concurrent mark-sweep generation:
   capacity = 715849728 (682.6875MB)
   used     = 115282968 (109.9424057006836MB)
   free     = 600566760 (572.7450942993164MB)
   16.104353119206607% used
Perm Generation:
   capacity = 168427520 (160.625MB)
   used     = 168178312 (160.38733673095703MB)
   free     = 249208 (0.23766326904296875MB)
   99.85203843172422% used

52703 interned Strings occupying 5899960 bytes.

可以很清楚的看到Java堆中各個區域目前的情況。

-histo:列印堆的物件統計,包括物件數、記憶體大小等等 (因為在dump:live前會進行full gc,如果帶上live則只統計活物件,因此不加live的堆大小要大於加live堆的大小 )

[email protected] etc]# jmap -histo:live 29544 | more
Picked up _JAVA_OPTIONS: -Dawt.useSystemAAFontSettings=lcd

 num     #instances         #bytes  class name
----------------------------------------------
   1:        294647       42231088  <constMethodKlass>
   2:        294647       37726512  <methodKlass>
   3:         30310       32955000  <constantPoolKlass>
   4:         92965       27338592  [B
   5:        254526       26667336  [C
   6:         30310       21857304  <instanceKlassKlass>
   7:         24015       17222656  <constantPoolCacheKlass>
   8:         89222        6150624  [Ljava.lang.Object;
   9:        250330        6007920  java.lang.String
  10:         50382        4030560  java.lang.reflect.Method
  11:         44966        3683408  [Ljava.util.HashMap$Entry;
  12:         82747        3309880  java.util.LinkedHashMap$Entry
  13:          5129        3286856  <methodDataKlass>
  14:         99275        3176800  java.util.concurrent.ConcurrentHashMap$HashEntry
  15:         98922        3165504  java.util.HashMap$Entry
  16:         31965        3020128  java.lang.Class
  17:         47367        2341800  [[I
  18:         40473        2188416  [S
  19:         25680        1438080  java.util.LinkedHashMap
  20:         23419        1234360  [Ljava.lang.String;
  21:          7983        1145488  [I
  22:         44966        1079184  java.util.HashMap$FrontCache
  23:          8249        1064896  [Ljava.util.concurrent.ConcurrentHashMap$HashEntry;
  24:         21452        1029696  org.apache.catalina.loader.ResourceEntry
  25:         23879         955160  java.lang.ref.SoftReference
  26:         29514         944448  java.lang.ref.WeakReference
  27:         38989         935736  java.util.ArrayList

xml class name是物件型別,說明如下:

B byte
C char
D double
F float
I int
J long
Z boolean
[ 陣列,如[I表示int[]
[L+類名 其他物件

-dump:匯出記憶體轉儲快照

常用格式:

-dump::live,format=b,file= pid
dump:堆到檔案
format:指定輸出格式
live:指明是活著的物件
file:指定檔名

dump.hprof這個字尾是為了後續可以直接用MAT(Memory Anlysis Tool)開啟。

-finalizerinfo:列印等待回收物件的資訊

[[email protected] home]# jmap -finalizerinfo 29544
Picked up _JAVA_OPTIONS: -Dawt.useSystemAAFontSettings=lcd
Attaching to process ID 29544, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 24.71-b01
Number of objects pending for finalization: 0

可以看到當前F-QUEUE佇列中並沒有等待Finalizer執行緒執行finalizer方法的物件。

-F:強制模式。如果指定的pid沒有響應,請使用jmap -dump或jmap -histo選項。此模式下,不支援live子選項。

jhat命令:

作用:

jhat(JVM Heap Analysis Tool)命令是與jmap搭配使用,用來分析jmap生成的dump,jhat內建了一個微型的HTTP/HTML伺服器,生成dump的分析結果後,可以在瀏覽器中檢視。在此要注意,一般不會直接在伺服器上進行分析,因為jhat是一個耗時並且耗費硬體資源的過程,一般把伺服器生成的dump檔案複製到本地或其他機器上進行分析。

命令格式:

jhat [dumpfile]

命令引數:

-stack false|true 

關閉物件分配呼叫棧跟蹤(tracking object allocation call stack)。 如果分配位置資訊在堆轉儲中不可用. 則必須將此標誌設定為 false. 預設值為 true.

-refs false|true

關閉物件引用跟蹤(tracking of references to objects)。 預設值為 true. 預設情況下, 返回的指標是指向其他特定物件的物件,如反向連結或輸入引用(referrers or incoming references), 會統計/計算堆中的所有物件。

-port port-number

設定 jhat HTTP server 的埠號. 預設值 7000.
-exclude exclude-file

指定物件查詢時需要排除的資料成員列表檔案(a file that lists data members that should be excluded from the reachable objects query)。 例如, 如果檔案列列出了 java.lang.String.value , 那麼當從某個特定物件 Object o 計算可達的物件列表時, 引用路徑涉及 java.lang.String.value 的都會被排除。

-baseline exclude-file

指定一個基準堆轉儲(baseline heap dump)。 在兩個 heap dumps 中有相同 object ID 的物件會被標記為不是新的(marked as not being new). 其他物件被標記為新的(new). 在比較兩個不同的堆轉儲時很有用.

-debug int

設定 debug 級別. 0 表示不輸出除錯資訊。 值越大則表示輸出更詳細的 debug 資訊.

-version

啟動後只顯示版本資訊就退出
-J< flag >

因為 jhat 命令實際上會啟動一個JVM來執行, 通過 -J 可以在啟動JVM時傳入一些啟動引數. 例如, -J-Xmx512m 則指定執行 jhat 的Java虛擬機器使用的最大堆記憶體為 512 MB. 如果需要使用多個JVM啟動引數,則傳入多個 -Jxxxxxx.

示例:

$ jhat -J-Xmx512m dump.hprof
  eading from dump.hprof...
  Dump file created Fri Mar 11 17:13:42 CST 2016
  Snapshot read, resolving...
  Resolving 271678 objects...
  Chasing references, expect 54 dots......................................................
  Eliminating duplicate references......................................................
  Snapshot resolved.
  Started HTTP server on port 7000
  Server is ready.

中間的-J-Xmx512m是在dump快照很大的情況下分配512M記憶體去啟動HTTP伺服器,執行完之後就可在瀏覽器開啟Http://localhost:7000進行快照分析 堆快照分析主要在最後面的Heap Histogram裡,裡面根據class列出了dump的時候所有存活物件。

分析同樣一個dump快照,MAT需要的額外記憶體比jhat要小的多的多,所以建議使用MAT來進行分析,當然也看個人偏好。
分析

All classes including platform
Show all members of the rootset
Show instance counts for all classes (including platform)
Show instance counts for all classes (excluding platform)
Show heap histogram
Show finalizer summary
Execute Object Query Language (OQL) query

一般檢視堆異常情況主要看這個兩個部分: Show instance counts for all classes (excluding platform),平臺外的所有物件資訊。如下圖:

這裡寫圖片描述

Show heap histogram 以樹狀圖形式展示堆情況。如下圖:

這裡寫圖片描述

具體排查時需要結合程式碼,觀察是否大量應該被回收的物件在一直被引用或者是否有佔用記憶體特別大的物件無法被回收。

一般情況,會down到客戶端用工具來分析

jstack命令

jstack用於生成java虛擬機器當前時刻的執行緒快照。執行緒快照是當前java虛擬機器內每一條執行緒正在執行的方法堆疊的集合,生成執行緒快照的主要目的是定位執行緒出現長時間停頓的原因,如執行緒間死鎖、死迴圈、請求外部資源導致的長時間等待等。

執行緒出現停頓的時候通過jstack來檢視各個執行緒的呼叫堆疊,就可以知道沒有響應的執行緒到底在後臺做什麼事情,或者等待什麼資源。 如果java程式崩潰生成core檔案,jstack工具可以用來獲得core檔案的java stack和native stack的資訊,從而可以輕鬆地知道java程式是如何崩潰和在程式何處發生問題。

另外,jstack工具還可以附屬到正在執行的java程式中,看到當時執行的java程式的java stack和native stack的資訊, 如果現在執行的java程式呈現hung的狀態,jstack是非常有用的。

命令格式

jstack [option] LVMID

option引數

-F : 當正常輸出請求不被響應時,強制輸出執行緒堆疊
-l : 除堆疊外,顯示關於鎖的附加資訊
-m : 如果呼叫到本地方法的話,可以顯示C/C++的堆疊

示例

[email protected] home]# jstack -l 29544 | more
Picked up _JAVA_OPTIONS: -Dawt.useSystemAAFontSettings=lcd
2017-12-15 10:49:21
Full thread dump Java HotSpot(TM) 64-Bit Server VM (24.71-b01 mixed mode):

"Attach Listener" daemon prio=10 tid=0x00007f2bf4002000 nid=0x2f4f waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
    - None

"Abandoned connection cleanup thread" daemon prio=10 tid=0x00007f2bac1fa000 nid=0x5e45 in Object.wait() [0x00007f2c1c672000]
   java.lang.Thread.State: TIMED_WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:135)
    - locked <0x00000000cab2d240> (a java.lang.ref.ReferenceQueue$Lock)
    at com.mysql.jdbc.AbandonedConnectionCleanupThread.run(AbandonedConnectionCleanupThread.java:43)

   Locked ownable synchronizers:
    - None

分析

執行緒狀態

NEW,未啟動的。不會出現在Dump中。
RUNNABLE,在虛擬機器內執行的。
BLOCKED,受阻塞並等待監視器鎖。
WATING,無限期等待另一個執行緒執行特定操作。
TIMED_WATING,有時限的等待另一個執行緒的特定操作。
TERMINATED,已退出的。

Monitor

在多執行緒的 JAVA程式中,實現執行緒之間的同步,就要說說 Monitor。 Monitor是 Java中用以實現執行緒之間的互斥與協作的主要手段,它可以看成是物件或者 Class的鎖。每一個物件都有,也僅有一個 monitor。下 面這個圖,描述了執行緒和 Monitor之間關係,以 及執行緒的狀態轉換圖:

這裡寫圖片描述

進入區(Entrt Set):表示執行緒通過synchronized要求獲取物件的鎖。如果物件未被鎖住,則迚入擁有者;否則則在進入區等待。一旦物件鎖被其他執行緒釋放,立即參與競爭。

擁有者(The Owner):表示某一執行緒成功競爭到物件鎖。

等待區(Wait Set):表示執行緒通過物件的wait方法,釋放物件的鎖,並在等待區等待被喚醒。

從圖中可以看出,一個 Monitor在某個時刻,只能被一個執行緒擁有,該執行緒就是 “Active Thread”,而其它執行緒都是 “Waiting Thread”,分別在兩個佇列 “ Entry Set”和 “Wait Set”裡面等候。在 “Entry Set”中等待的執行緒狀態是 “Waiting for monitor entry”,而在 “Wait Set”中等待的執行緒狀態是 “in Object.wait()”。 先看 “Entry Set”裡面的執行緒。我們稱被 synchronized保護起來的程式碼段為臨界區。當一個執行緒申請進入臨界區時,它就進入了 “Entry Set”佇列。對應的 code就像:

synchronized(obj) {
.........
}

呼叫修飾

表示執行緒在方法呼叫時,額外的重要的操作。執行緒Dump分析的重要資訊。修飾上方的方法呼叫。

locked <地址> 目標:使用synchronized申請物件鎖成功,監視器的擁有者。

waiting to lock <地址> 目標:使用synchronized申請物件鎖未成功,在迚入區等待。

waiting on <地址> 目標:使用synchronized申請物件鎖成功後,釋放鎖幵在等待區等待。

parking to wait for <地址> 目標

locked

at oracle.jdbc.driver.PhysicalConnection.prepareStatement
- locked <0x00002aab63bf7f58> (a oracle.jdbc.driver.T4CConnection)
at oracle.jdbc.driver.PhysicalConnection.prepareStatement
- locked <0x00002aab63bf7f58> (a oracle.jdbc.driver.T4CConnection)
at com.jiuqi.dna.core.internal.db.datasource.PooledConnection.prepareStatement

通過synchronized關鍵字,成功獲取到了物件的鎖,成為監視器的擁有者,在臨界區內操作。物件鎖是可以執行緒重入的。

waiting to lock

at com.jiuqi.dna.core.impl.CacheHolder.isVisibleIn(CacheHolder.java:165)
- waiting to lock <0x0000000097ba9aa8> (a CacheHolder)
at com.jiuqi.dna.core.impl.CacheGroup$Index.findHolder
at com.jiuqi.dna.core.impl.ContextImpl.find
at com.jiuqi.dna.bap.basedata.common.util.BaseDataCenter.findInfo

通過synchronized關鍵字,沒有獲取到了物件的鎖,執行緒在監視器的進入區等待。在呼叫棧頂出現,執行緒狀態為Blocked。

waiting on

at java.lang.Object.wait(Native Method)
- waiting on <0x00000000da2defb0> (a WorkingThread)
at com.jiuqi.dna.core.impl.WorkingManager.getWorkToDo
- locked <0x00000000da2defb0> (a WorkingThread)
at com.jiuqi.dna.core.impl.WorkingThread.run

通過synchronized關鍵字,成功獲取到了物件的鎖後,呼叫了wait方法,進入物件的等待區等待。在呼叫棧頂出現,執行緒狀態為WAITING或TIMED_WATING。

parking to wait for

park是基本的執行緒阻塞原語,不通過監視器在物件上阻塞。隨concurrent包會出現的新的機制,不synchronized體系不同。

執行緒動作
執行緒狀態產生的原因

runnable:狀態一般為RUNNABLE。
in Object.wait():等待區等待,狀態為WAITING或TIMED_WAITING。
waiting for monitor entry:進入區等待,狀態為BLOCKED。
waiting on condition:等待區等待、被park。
sleeping: