jvm第五節-效能調優工具使用
[[email protected] bin]# ./jmap -permstat 568
Attaching to process ID 568, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 20.45-b01
16140 intern Strings occupying 1783912 bytes.
finding class loader instances ..Finding object size using Printezis bits and skipping over...
Finding object size using Printezis bits and skipping over...
Finding object size using Printezis bits and skipping over...
Finding object size using Printezis bits and skipping over...
done.
computing per loader stat ..done.
please wait.. computing liveness............................liveness analysis may be inaccurate ...
class_loader classes bytes parent_loader alive? type
<bootstrap> 2493 14855744 null live <internal>
0x00000000e0773800 1 1944 0x00000000e01c99b8 dead sun/reflect/ [email protected]
total = 207 7595 48487296 N/A alive=26, dead=181 N/A
C.使用jmap -heap pid檢視程序堆記憶體使用情況,包括使用的GC演算法、堆配置引數和各代中堆記憶體使用情況。比如下面的例子:
[[email protected] bin]# ./jmap -heap 568
Attaching to process ID 568, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 20.45-b01
using thread-local object allocation.
Parallel GC with 4 thread(s)
Heap Configuration:
MinHeapFreeRatio = 40
MaxHeapFreeRatio = 70
MaxHeapSize = 536870912 (512.0MB)
NewSize = 1310720 (1.25MB)
MaxNewSize = 268435456 (256.0MB)
OldSize = 5439488 (5.1875MB)
NewRatio = 2
SurvivorRatio = 8
PermSize = 67108864 (64.0MB)
MaxPermSize = 134217728 (128.0MB)
Heap Usage:
PS Young Generation
Eden Space:
capacity = 88145920 (84.0625MB)
used = 1621408 (1.546295166015625MB)
free = 86524512 (82.51620483398438MB)
1.8394589335501859% used
From Space:
capacity = 327680 (0.3125MB)
used = 0 (0.0MB)
free = 327680 (0.3125MB)
0.0% used
To Space:
capacity = 655360 (0.625MB)
used = 0 (0.0MB)
free = 655360 (0.625MB)
0.0% used
PS Old Generation
capacity = 178978816 (170.6875MB)
used = 15780800 (15.04974365234375MB)
free = 163198016 (155.63775634765625MB)
8.817132861131453% used
PS Perm Generation
capacity = 67371008 (64.25MB)
used = 48657272 (46.40319061279297MB)
free = 18713736 (17.84680938720703MB)
72.22286476699294% used
[ [email protected] bin]#
D.使用jmap -histo[:live] pid檢視堆記憶體中的物件數目、大小統計直方圖,如果帶上live則只統計活物件,如下:
E.用jmap把程序記憶體使用情況dump到檔案中,再用jhat分析檢視。jmap進行dump命令格式如下: jmap -dump:format=b,file=dumpFileName pid ./jmap -dump:format=b,file=/usr/local/my.bin[[email protected] bin]# ./jmap -histo:live 568 | more num #instances #bytes class name ---------------------------------------------- 1: 66979 10485224 <constMethodKlass> 2: 66979 9119528 <methodKlass> 3: 6324 7213368 <constantPoolKlass> 4: 106075 6052696 <symbolKlass> 5: 44944 5260600 [C 6: 6324 4773896 <instanceKlassKlass> 7: 5526 4452336 <constantPoolCacheKlass> 8: 9718 3255512 [B 9: 49626 1588032 java.lang.String 10: 1985 1329544 <methodDataKlass> 11: 6876 715104 java.lang.Class 12: 8684 615896 [S 13: 6854 603264 [Ljava.util.HashMap$Entry; 14: 18715 598880 java.util.HashMap$Entry 15: 10192 507944 [[I 16: 6619 467656 [I 17: 5120 450560 java.lang.reflect.Method 18: 8701 434216 [Ljava.lang.Object; 19: 10402 416080 java.util.LinkedHashMap$Entry 20: 7728 309120 java.util.concurrent.ConcurrentHashMap$Segment 21: 523 305432 <objArrayKlassKlass> 22: 7921 253472 java.util.concurrent.locks.ReentrantLock$NonfairSync 23: 7728 242408 [Ljava.util.concurrent.ConcurrentHashMap$HashEntry; 24: 5494 219760 java.lang.ref.SoftReference 25: 3660 175680 java.util.HashMap 26: 4740 151680 java.lang.ref.WeakReference 27: 4728 148752 [Ljava.lang.String; 28: 2662 127776 org.apache.catalina.loader.ResourceEntry 29: 5275 126600 java.util.ArrayList 30: 1407 101304 java.lang.reflect.Constructor
[[email protected] ~]#./ jmap -dump:format=b,file=my.bin 568
Dumping heap to /root/my.bin ...
Heap dump file created
jhat -port 9998 /usr/local/my.bin,埠預設是7000
5.jhat
jhat是sun提供的dump分析工具,上面講過分析dump的工具還有MAT( Eclipse Memory Analyzer tool)、IBM HeapAnalyzer等,一般這個命令不太用到,是因為分析dump是個既耗時又耗機器資源的過程,第二個原因是這個工具比較簡陋,沒有MAT( Eclipse Memory Analyzer tool)、IBM HeapAnalyzer這些專業和強大。
命令格式:
jhat file
使用樣例:
防止影響服務,所以在本地windows下使用,先匯出dump檔案
./jmap -dump:format=b,file=my.bin 568
Dumping heap to my.bin ...
Heap dump file created
然後分析:
./jhat my.bin
Reading from my.bin...
Dump file created Thu Feb 18 16:20:49 CST 2016
Snapshot read, resolving...
Resolving 2532914 objects..
Chasing references, expect 1 dots.
Eliminating duplicate references.
Snapshot resolved.
Started HTTP server on port 7000
Server is ready.
載在瀏覽器中輸入localhost:7000檢視結果,如下圖
6.jstack
jstack用於打印出給定的java程序ID或core file或遠端除錯服務的Java堆疊資訊,如果是在64位機器上,需要指定選項"-J-d64",Windows的jstack使用方式只支援以下的這種方式:
如果java程式崩潰生成core檔案,jstack工具可以用來獲得core檔案的java stack和native stack的資訊,從而可以輕鬆地知道java程式是如何崩潰和在程式何處發生問題。另外,jstack工具還可以附屬到正在執行的java程式中,看到當時執行的java程式的java stack和native stack的資訊, 如果現在執行的java程式呈現hung的狀態,jstack是非常有用的。
命令格式 :
jstack [ option ] pid
引數說明:
-F當’jstack [-l] pid’沒有相應的時候強制列印棧資訊
-l長列表. 列印關於鎖的附加資訊,例如屬於java.util.concurrent的ownable synchronizers列表.
-m列印java和native c/c++框架的所有棧資訊.
使用樣例:
[[email protected] ~]# jstack -l 21742
[email protected] bin]# printf "%x\n" 21742
238
[[email protected] bin]# ./jstack 21742|grep 238
- waiting on <0x00000000e085f238> (a java.lang.ref.ReferenceQueue$Lock)
- locked <0x00000000e085f238> (a java.lang.ref.ReferenceQueue$Lock)
[[email protected] bin]# printf "%x\n" 568
jstack主要用來檢視某個Java程序內的執行緒堆疊資訊。語法格式如下:
jstack [option] pid
jstack [option] executable core
jstack [option] [[email protected]]remote-hostname-or-ip
命令列引數選項說明如下:
-l long listings,會打印出額外的鎖資訊,在發生死鎖時可以用jstack -l pid來觀察鎖持有情況
-m mixed mode,不僅會輸出Java堆疊資訊,還會輸出C/C++堆疊資訊(比如Native方法)
jstack可以定位到執行緒堆疊,根據堆疊資訊我們可以定位到具體程式碼,所以它在JVM效能調優中使用得非常多。下面我們來一個例項找出某個Java程序中最耗費CPU的Java執行緒並定位堆疊資訊,用到的命令有ps、top、printf、jstack、grep。
第一步先找出Java程序ID,我部署在伺服器上的Java應用名稱為my:
得到程序ID為21711,第二步找出該程序內最耗費CPU的執行緒,可以使用ps -Lfp pid或者ps -mp pid -o THREAD, tid, time或者top -Hp pid,我這裡用第三個,輸出如下
TIME列就是各個Java執行緒耗費的CPU時間,CPU時間最長的是執行緒ID為21742的執行緒,用
printf "%x\n" 21742
得到21742的十六進位制值為54ee,下面會用到。
OK,下一步終於輪到jstack上場了,它用來輸出程序21711的堆疊資訊,然後根據執行緒ID的十六進位制值grep,如下:
./jstack 21711 | grep 54ee
"PollIntervalRetrySchedulerThread" prio=10 tid=0x00007f950043e000 nid=0x54ee in Object.wait()
死鎖程式碼如下:
// 執行緒處於無線等待中
getLog().info("Thread [" + getName() + "] is idle waiting...");
schedulerThreadState = PollTaskSchedulerThreadState.IdleWaiting;
long now = System.currentTimeMillis();
long waitTime = now + getIdleWaitTime();
long timeUntilContinue = waitTime - now;
synchronized(sigLock) {
try {
if(!halted.get()) {
sigLock.wait(timeUntilContinue);
}
}
catch (InterruptedException ignore) {
}
}