|
Websphere性能分析與優(yōu)化 ——從Heapdump淺談JVM堆設(shè)置
不同版本的JDK可以設(shè)置的JVM堆大小是不一樣的,而JVM堆的大小直接制約系統(tǒng)的性能,合理設(shè)置每個應(yīng)用服務(wù)器中的JVM堆,在系統(tǒng)性能優(yōu)化中是十分關(guān)鍵的一步。 一般來說,JVM堆可設(shè)置的大小受其版本限制,可分為以下兩大類: 1、32位的JDK,JVM堆最大可設(shè)置到1.5G左右 2、64位的JDK,JVM堆大小暫無限制 那我們該如何調(diào)整JVM的堆大小呢?在Was上如何去設(shè)定一個合理的值且多大的值才算是合理的呢? 首先我們來了解下JVM堆大小對系統(tǒng)有哪些主要的影響,在JVM堆不足的情況下將會導(dǎo)致系統(tǒng): 1、頻繁的垃圾回收(引發(fā)系統(tǒng)資源緊張情況,集群環(huán)境下CPU資源消耗就更嚴(yán)重) 2、OOM,內(nèi)存溢出(out of memory) 系統(tǒng)繁忙時,一般都是在處理大量的客戶端請求,或是在進(jìn)行多個復(fù)雜的計算,它們都需要向JVM堆申請空間進(jìn)行對象的創(chuàng)建。在堆空間不足的情況下,應(yīng)用系統(tǒng)會出現(xiàn)以下一些情況,從而大大降低客戶的感知度: 1、請求操作響應(yīng)時間長 2、請求操作失敗,資源等待操作,內(nèi)存溢出 為了保證系統(tǒng)的性能,提高系統(tǒng)穩(wěn)定性,我們就需要對JVM堆的詳細(xì)使用情況刨根問底,以此估出一個合理的值來設(shè)置JVM堆大小。 有專家給出建議,Was每個Server的線程池不宜配置過大,一般建議值在50-120之間,而JVM堆則設(shè)置在2G內(nèi)。這個建議針對大部分系統(tǒng)都是適用的,如果在這個配置上系統(tǒng)運(yùn)行還出現(xiàn)性能問題,可先從應(yīng)用程序角度著手優(yōu)化。因為無論線程池的線程大小是多少,每個線程給系統(tǒng)帶來的主要壓力就是JVM堆資源的占用。 在32位的Java虛擬機(jī)上,JVM堆最大可設(shè)置到1.5G左右。假設(shè)請求從客戶端來到Was,Was從線程池中分配一個線程處理這個請求,同時從JVM堆空間申請相應(yīng)的資源進(jìn)行操作。假設(shè)這是一個上傳5MB的Excel的線程,那么在上傳與處理這個Excel過程中,線程占用的JVM堆的資源會越來越多,甚至有可能需要向JVM堆申請超過30MB的空間(當(dāng)然30MB的堆空間不是絕對,這與代碼設(shè)計密切相關(guān),如果到Excel上傳過程中,還要進(jìn)行分析,封裝,持久化等操作)。這種情況下,再有50個類似的上傳Excel的線程,系統(tǒng)性能就會受到影響,因為在線程操作結(jié)束前,JVM堆資源被大量占用且無法快速釋放,系統(tǒng)剩余可分配的JVM堆空間越來越少,如再有其它線程繼續(xù)申請堆空間資源的話,就需要等待垃圾回收或者資源空間的創(chuàng)建了。 因此為了保證系統(tǒng)的性能,我們首先要保證JVM堆剩余可分配空間的大小。除了加大JVM堆的設(shè)置外(可考慮集群方式降低單Server的壓力),我們還要從系統(tǒng)設(shè)計與應(yīng)用程序代碼優(yōu)化入手,避免資源相互占用,資源調(diào)用后可快速釋放。 應(yīng)如何優(yōu)化應(yīng)用代碼呢?在實際項目中,許多應(yīng)用系統(tǒng)的工期都十分緊張,從需求調(diào)研到系統(tǒng)上線,可能僅有個把月的時間。由于復(fù)雜的業(yè)務(wù)邏輯和緊張的工作期限,在編碼過程中難免都會出現(xiàn)一些漏洞,這些漏洞問題可能因為功能交叉關(guān)聯(lián),過于復(fù)雜,在測試階段不能重現(xiàn),直到投入生產(chǎn)使用中才發(fā)現(xiàn),并且隨著系統(tǒng)功能不斷增加,關(guān)聯(lián)越來越多,有些問題會成為影響性能的根源,讓我們猝不及防!因此我們需要增加數(shù)據(jù)監(jiān)控這一過程,其中可以通過Heapdump文件收集生產(chǎn)上每個Server的JVM堆中對象空間詳細(xì)分配情況作為參考,進(jìn)行代碼優(yōu)化與堆大小設(shè)置。 Heapdump文件主要用于記錄JVM堆對象的詳細(xì)信息,在JVM堆接收到轉(zhuǎn)儲命令時產(chǎn)生,其相當(dāng)于JVM堆某一時間切面的詳細(xì)信息,也可理解為記錄對象在JVM中詳細(xì)痕跡的一個日志。通過分析Heapdump文件,我們可了解到各個對象的大小,及對象之間的關(guān)聯(lián)關(guān)系等。 Heapdump文件一般比較大,文本查看工具已不能滿足我們的要求,為了迅速從文件中找占用資源最多的對象,我們需要借助一些專業(yè)的工具來進(jìn)行分析。如: 1、 IBM HeapAnalyzer 該軟件采用樹形方式描述JVM堆,目前已出到V4.08版本。分析過程需要一層層展開查閱,尋找到資源消耗最大的關(guān)鍵對象。 通過該工具,我們可以詳細(xì)了解到對象之間的關(guān)系,根據(jù)關(guān)系推斷資源消耗大的對象主要存儲了哪些內(nèi)容,由哪些關(guān)鍵類去觸發(fā)。 在左圖中我們看到龐大的堆棧樹,若一層層展開查閱與分析,很容易就看到眼冒金星。因此我們需要使用一些小功能去幫助分析整個堆載信息,如: (1)Go to the largest drop in the subtrees (使用該功能,可快速查詢到堆棧樹下最大的可疑對象,然后逐層向上分析) (2)List same type(查看相同類型的對象,在死循環(huán)情況下,可以快速定位問題) 2、 MDD4J工具 同樣是分析內(nèi)存堆使用情況的工具,但較HeapAnalyzer有較大不同,該工具會在裝載文件的過程中進(jìn)行智能分析,然后給出相應(yīng)的建議,縮小我們的分析范圍。
如:可疑內(nèi)存對象視圖、類型視圖、實例視圖、樹形視圖等。 簡易分析方法: (1)先通過可疑內(nèi)存對象視圖,了解到究竟哪些對象存在泄露的可能性 (2)再通過樹形視圖詳細(xì)分析每個可疑泄露對象,展開每一層節(jié)點,分析是否存在內(nèi)存泄露的可能性。一般來說,我們都是根據(jù)經(jīng)驗查找非JDK,或者IBM對象的對象,而直接查找項目或項目使用到的組件的對象進(jìn)行分析,查看其關(guān)系。
無論是哪個工具,通過其提供的信息,我們可認(rèn)識到JVM堆中的內(nèi)容就是一棵龐大的堆棧樹,我們可先排除Was中間件的問題,從項目代碼或者使用到的組件代碼進(jìn)行分析,搜索可疑泄漏對象,一步步詳細(xì)分析下去,關(guān)鍵步驟就是要找到以下一些重要對象:
收集到以上信息后,我們就可以進(jìn)一步結(jié)合項目代碼去分析問題所在。 為了保證分析質(zhì)量,我們需要采集連續(xù)多個時間段的Heapdump文件。因為有可能在一些復(fù)雜操作過程中,所需創(chuàng)建的對象比較多,但它們最終會被垃圾回收的功能回收,因此它們并不一定是觸發(fā)性能問題的主要根源,而是在大并發(fā)請求或者資源不足的情況才會引起性能問題。 分析Heapdump文件時,并非每個可疑泄漏對象都有問題,我們要分析與檢查每個泄漏源堆棧前后所涉及的對象,通過對象的大小與業(yè)務(wù)邏輯分析,判斷這些對象設(shè)計與引用是否合理。在JVM堆中主要存儲了兩種對象,一種是臨時對象,一種是永久保存的對象。臨時對象在失去引用的情況下,才會由垃圾回收功能回收空間。而永久保存對象,從JVM的進(jìn)程創(chuàng)建的開始,就一直存儲在JVM堆中,直到進(jìn)程結(jié)束后才釋放。因此我們檢查與分析Heapdump文件過程中,可以結(jié)合項目代碼進(jìn)行判斷。 我們可以通過Heapdump生成方式的不同,采用不同策略去檢查與分析。
l JVM堆空間不足(內(nèi)存不足) l 死鎖,程序死循環(huán)導(dǎo)致與線程資源相互占用 l 內(nèi)部錯誤
分析過程我們可檢查是否存在死鎖問題,再檢查堆空間對象大小是否合理。
l 靜態(tài)變量:將對象存入靜態(tài)變量中實現(xiàn)緩存是常見的手段,其優(yōu)勢是避免了資源的重復(fù)讀取,但是不斷將對象保存到靜態(tài)變量而沒有顯示釋放,容易導(dǎo)致內(nèi)存溢出,或者剩余可用堆空間不足(所以有些系統(tǒng)雖然進(jìn)行了垃圾回收的優(yōu)化,但性能提升不明顯,這主要是因為堆空間可用率不高); l Threadlocal:Was采用了連接池方式,web線程的管理是由Was負(fù)責(zé)的,如果大量使用Threadlocal來存儲臨時對象,并且在線程退出的時候不顯示銷毀,也會導(dǎo)致JVM堆可用空間不斷減少,其結(jié)果和第一點一樣; l 類加載問題:每次不重新啟動Sever,而是直接重新啟動應(yīng)用,多次操作后JVM堆剩余空間越來越少,進(jìn)而引發(fā)內(nèi)存泄露問題(這主要是應(yīng)用程序中存在靜態(tài)對象在類裝載過程建立了引用的關(guān)系,即使停止了應(yīng)用,但是由于引用關(guān)系未顯示釋放,導(dǎo)致對象一直殘留在JVM堆中,只有重啟Server才可以銷毀) 。 給JVM堆設(shè)置一個合理的數(shù)值,不一定能給系統(tǒng)的性能帶來巨大飛躍,但這卻是系統(tǒng)性能調(diào)優(yōu)過程中必不可少的一步。如果系統(tǒng)要運(yùn)行得更加穩(wěn)定與支撐更大的并發(fā)請求操作,我們需要從各方面著手檢查與優(yōu)化,Heapdump文件可以給到我們很大的幫助。結(jié)合垃圾回收日志,我們就可以輕松掌握到JVM堆詳細(xì)情況,以便為系統(tǒng)設(shè)置合理的堆值。 |
|
|