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