天天看點

使用JRockit Mission Control進行性能分析和調優

Mission Control是BEA JRockit JVM自帶的一組以極低的開銷來監控、管理和分析生産環境中的應用程式的工具。它包括三個獨立的應用程式:記憶體洩漏監測器(Memory Leak Detector)、JVM運作時分析器(Runtime Analyzer)和管理控制台(Management Console)。BEA從JRockit R26版本就開始捆綁這個工具套件,目前最新的版本是3.0。最近我們使用其中的Runtime Analyzer對國内某著名行業解決方案進行性分析和調優。

JRockit Runtime Analyzer(JRA)是一個JVM分析器,是一個随需應變的“動态記錄器”。它記錄了Java應用程式和JVM在一段預定的時間内的詳細記錄。然後通過JRA應用程式對記錄下來的檔案進行離線分析。所記錄的資料包括對方法的調用跟蹤、錯誤的同步、鎖定的分析,還有垃圾收集統計資訊,優化決策以及對象統計資訊和其他重要的應用程式/JVM行為。它的目的是讓JRockit開發人員能夠找到良好的方法來基于現實應用程式優化JVM,對于幫助客戶在生産和開發環境中解決問題十分有用。

2.性能資料分析和調優

在本次項目中,操作|A和操作B的百人并發腳本執行完成的時間接近兩分鐘,是以我們使用JRA進行了2分鐘(120秒)的記錄。在GC正常資訊中,我們發現在短短兩分鐘時間内,垃圾收集的總數高達365次,而由此造成的暫停時間有42.5秒之多。也就是說35%的執行時間是在做垃圾收集。

因為最大堆尺寸已經設定成1024M,對于32位作業系統上的Java應用已經是足夠大了(在IA32構架下,由于作業系統給每個程序的最大記憶體尋址空間為1.8G,是以最大堆尺寸不能超過1.8G),是以堆的大小并不是造成頻繁垃圾收集的原因。那麼在高并發度的場景下,可能的影響因素很可能是Nursery大小。

Nursery 也稱為新代,是指運作分代式垃圾收集器時,在堆中配置設定 新對象 的可用塊區域。當 Nursery 變滿時,會在新垃圾收集中單獨對其進行垃圾收集。Nursery 大小決定了新收集的頻率和持續時間。較大 Nursery 會降低收集的頻率,但是會稍微增加每個新收集的持續時間。 Nursery 之是以具有價值,是因為 Java 應用程式中的大多數對象都是在新代中夭亡的。與收集整個堆相比,應首選從新空間中收集垃圾,因為該收集過程的開銷更低,而且在觸發收集時,新空間中的大多數對象均已死亡。在新收集過程中,JVM 首先确定 Nursery 中的哪些對象是活動的,此後将它們提升到舊空間,并釋放 Nursery,供配置設定新的小對象使用。

Nursery的預設預設值是10M/CPU,對于我們Clovertown伺服器來說,隻有20M。由于出現頻繁收集的情況,那麼我們推斷是由于Nursery的預設值太低的原因。一方面在高并發使用者的場景下,肯定是有大量的新對象産生,那麼Nursery的空閑空間很容易就被耗盡。是以Nursery發生垃圾收集頻率就會比較高。另一方面更短的垃圾收集間隔會使得新對象在Nursery的存活率提高因為很多新對象可能還沒來得及使用完畢就已經發生垃圾收集。這樣更多的對象會被提升到舊代,使得舊代的對象也會急劇增加,進而使得舊代發生垃圾收集的頻率也增加。

因為JRockit JVM可以使用-Xns:<size>來設定Nursery的尺寸,我們要在保證垃圾回收停頓時間(garbage collection-pause)盡可能短的同時,盡量加大Nursery的尺寸,這在建立了大量的臨時對象時尤其重要。推薦值是最大堆尺寸的10%,是以我們在JRockit的運作時參數上添加了 –Xns100m。再次運作腳本後,JRA收集的資訊顯示GC暫停時間驟降到15.3s,次數也有所減少,降到296:

Nursery大小

20M(預設值)

100M

GC暫停時間

42.5s

15.3s

垃圾收集的總數

365

296

平均暫停時間

116ms

52ms

此外,我們從方法資訊中可以看到調用次數最多耗時間最長的兩個方法分别是jrockit.vm.Locks.monitorEnterSecondStage和com.ABC.StateManager.makeState兩個方法。展開前置任務後發現調用這兩個方法最多的方法是com.ABC.SqlQueryAction.query。而jrockit.vm.Locks.monitorEnterSecondStage顯然是JRockit實作鎖機制的特定的API。是以我們懷疑是對資料庫的操作時有資源互斥的現象發現。

考慮到高并發使用者的場景下,對資料庫操作的并發度也很高,是以對資料庫連接配接的争用比較激烈。我們察看了一下當時WebLogic JDBC的配置,發現connection pool的大小隻是預設值20,相對來說偏小了,對性能會有一定的影響。是以我們增大connection pool的大小到100。重新運作測試腳本後發現性能有較大提升。

JDBC connection size 20  w/ default nursery

JDBC connection size 100 w/ 100M nursery

Increase %

操作A

22.125

12.079

83%

操作B

35.195

21.773

62%

在性能調優完成後,我們又進行了功能測試(回歸測試),以驗證上述改動沒有影響系統的功能性正确。

四、小結

其實利用Mission Control對Java應用進行調優并不難,對吧?希望本次性能分析調優的過程可以給大家一些啟發,今後可以應用到日常工作中。

本文轉自Intel_ISN 51CTO部落格,原文連結:http://blog.51cto.com/intelisn/130730,如需轉載請自行聯系原作者