引言
內存泄漏的成本非常高昂,經常伴隨著產品停機時間和零碎的部署安排。遺憾的是,合適測試解決方案的成本也十分高昂,客戶經常不愿意或者不能對必要的資源進行投資。
為了更加清楚起見,解決內存泄漏的最佳方法是在測試時檢測并解決它們。理想情況下,應當進行測試安排,并且有一種與產品環境完全相同的測試環境,這種環境能夠驅動典型的和異常的工作負載,還應當有技術資源,他們具備專門進行系統測試的適當技能。這是盡可能確保完全轉換到產品的最佳方式。但是,設計和提供這樣一種環境,以及相關的文化變化,都不是本文的重點。
Java 中有四類常見的內存使用問題:
WebSphere Application Server 已經引入了兩種輔助技術,用以幫助客戶解決 Java 堆內存泄漏(對這些工具進行一定的擴展還可以解決由于內存資源不足所導致的問題,在本文中沒有比較這兩種問題的相似性)。
一般來說,當應用程序(由于程序邏輯錯誤)無意中保存對于不再需要的對象的引用時,會導致 Java 堆內存泄漏。這種無意對象引用阻止內置 Java 垃圾回收機制釋放由這些對象所使用的內存。這些內存泄漏的共同原因是:
由于內存資源不足而產生的內存使用問題可能是由于配置問題或系統容量問題所導致的。例如,在為 Java 虛擬機配置最大允許堆大小時所使用的 -Xmx 參數值過低,不能容納內存中的用戶會話總數?;蛘?,系統的物理內存過少,不能容納當前工作負載。本機內存泄漏是非 Java 代碼中的內存泄漏;例如,在 Type-II JDBC 驅動程序或者 Java 進程的地址空間中的非堆段內的碎片。
這是一篇為 Java 開發人員、系統管理員以及問題確定顧問撰寫的介紹性文章,這些人員使用部署在 IBM WebSphere Application Server 上的應用程序。
用于檢測內存泄漏根源的現有技術中所存在的問題
有大量導致內存泄漏的問題,它們對于系統管理員特別棘手:
傳統的 Java 內存泄漏根源檢測技術有十分顯著的性能負擔,可能不適于在生產環境中使用。這些技術通常包括堆轉儲分析、附加 Java 虛擬機分析器接口(Java Virtual Machine Tools Interface,JVMPI)或Java 虛擬機工具接口(Java Virtual Machine Tools Interface,JVMTI)代理,或者使用字節代碼插入來跟蹤向集合中的插入和刪除。
傳統的冗余方法,例如群集技術,只能在一定程度上有所幫助。內存泄漏將在群集成員中傳播。受影響的應用服務器的響應速度減緩了負載管理技術。這可能導致將請求路由到運行狀況更好的服務器,從而導致協調應用服務器崩潰。
一種典型的分析解決方案應當嘗試將應用程序移到一個隔離的測試環境中,在這個環境中應當可以重現問題并進行分析,而不會影響生產服務器。由于在這些測試環境中重現問題的難度很大,所以相關內存泄漏的成本增加了。
導致這些問題的原因在于傳統技術嘗試同時執行檢測和分析。
WebSphere 解決方案
WebSphere Application Server V6.0.2 及更高版本提供了一種兩階段解決方案,將 檢測 問題與分析 問題分離開來。
第一階段是輕量級內存泄漏檢測機制,運行于生產 WebSphere Application Server 運行時中。這一輕量級檢測技術使用成本較低,普遍可用的 Java 堆使用統計數字來監視內存使用趨勢,并提供內存泄漏的早期通知。這使管理員有時間準備適當的備份解決方案,并采用離線方式分析問題的根源,而不會存在那些在測試環境中進行重現所導致的問題,這些問題的成本很高,而且也很難解決。
此解決方案的第二階段是一個脫機工具:Memory Dump Diagnostic for Java (MDD4J),它在生產應用服務器之外分析堆轉儲。這是一個重量級脫機內存泄漏分析工具,它將多種現有堆轉儲分析工具整合在單一用戶界面中。
為了在檢測和分析之間架起一座橋梁,已經為在 IBM JDK 上運行的 WebSphere Application Server 提供了自動化堆轉儲生成工具。在檢測到一種內存泄漏方式之后,此工具將產生多重堆轉儲,它們可以與足夠的內存泄漏進行協調,以方便使用 MDD4J 的對比分析。此外,如果檢測到了 OutOfMemoryError,則將 IBM JDK 配置為自動產生堆轉儲。管理員應當建立負載平衡,或在低使用時間產生堆轉儲,以避免短時間內性能低下。
![]() ![]() |
![]()
|
內存泄漏檢測
輕量級內存泄漏檢測是通過監視自由內存中的下降趨勢而實現的。
泄漏可能非??焖?,也可能極其慢,所以短間隔和長間隔的內存使用趨勢都會被分析。此外,對于在垃圾收集周期之后近似內存使用中的下降趨勢也進行分析,以檢測在垃圾收集周期之后平均自由內存數低于特定門限的情況。這樣一種情景既可以是內存泄漏的一種標志,也可能表示正在一個資源過少的應用服務器上運行一個應用程序。這一輕量級內存泄漏檢測工具可用于從 6.0 版開始的所有 WebSphere Application Server 版本上,并可用于所有平臺。
此外,作為 iSeries® 平臺的特殊情況,WebSphere Application Server on iSeries 包含一些附加功能,用來檢測 Java 堆大小是否要擴展到 DASD上,并將向管理員發出警報,通知管理員是將發生這一現象,還是出現了以下情況之一:
zSeries® 在版本 6.0.2 中僅支持單一 Servant 拓撲,但在版本 6.1 中擴展為可以包含多個 Servant 拓撲。在 V6.0.2 中,單一 Servant 拓撲將內存泄漏檢測的范圍限制為問題確定或測試環境。
圖 1 顯示了由內存泄漏檢測特性所產生的示例通知。這一通知通過 JMX 送出,并顯示在管理控制臺中,且被記錄在服務器日志中。
自動堆轉儲生成工具(僅可用在 IBM JDK 上)在內存泄漏的證據非常明顯之后、但在應用程序由于 OutOfMemoryError 而崩潰之前產生堆轉儲。此工具可在足夠的內存泄漏之后生成一個第二堆轉儲。這兩個堆轉儲有助于使用 MDD4J 進行比較分析。
自動堆轉儲生成可以缺省啟用,也可以在適當時間通過 MBean 操作啟動。
WebSphere Extended Deployment
盡管在 WebSphere Application Server 和 WebSphere Application Server Network Deployment 中提供了輕量級內存泄漏檢測,并且其設計為即時可用,它還是完全可配置的,可以與高級自主管理器或自定義 JMX 客戶端交互。WebSphere Extended Deployment 是這種關系的一個例子。
WebSphere Extended Deployment 提供了許多配置內存泄漏檢測的策略。一種策略通過取得多個堆轉儲(使用工作負載管理來維護應用程序的性能)以進行分析,從而對內存泄漏通知做出反應。另一種策略簡單地監視應用服務器的內存水平何時達到臨界狀態,以在應用服務器崩潰之前對其進行重啟。
![]() ![]() |
![]()
|
內存泄漏分析
一旦已經檢測到了內存泄漏并且已經生成了堆轉儲,它們就可以被傳遞到生產服務器之外,轉到問題確定機器中進行分析。
Memory Dump Diagnostic for Java (MDD4J) 是一種脫機堆轉儲分析工具,其在確定內存泄漏的根源過程中提供幫助。這一分析機制確定了受懷疑的泄漏數據結構類和數據包。這一標識使系統管理員能夠將內存泄漏的根源縮小到有限幾個組件應用程序中。
WebSphere Application Server 提供了用于承載來自第三方 J2EE 應用程序的容器。當 Java 堆棧隨時間發展時,越來越多的抽象層和組件化被添加到基本 Java 應用程序以及WebSphere Application Server 堆棧中。這樣就對發生內存泄漏時進行問題確定造成了巨大的挑戰。對于一個遇到內存泄漏的系統管理員來說,承載著大量第三方應用程序的 WebSphere Application Server 就像是一個黑盒。在這種情況下,第一個步驟是將內存泄漏的根源限制到一個或幾個組件。根源通常位于一個發生故障的組件應用程序中。在 Memory Dump Diagnostic for Java 工具的分析結果的幫助下,系統管理員現在可以更快速地確定一個錯誤組件,而不需要來自 IBM 的任何支持。
一旦確定了發生故障的組件,系統管理員可以找到一位開發人員,他能夠在更小環境中重現這一問題,并使用調試器或日志記錄中的特定跟蹤語句來確定錯誤的源代碼方法,并對應用程序代碼或者配置進行必要的修改,以解決內存泄漏。有時,了解到故障組件或泄漏對象就足以使我們確定一些常見的配置問題。例如,查找大量的 HTTP 會話對象將會引導我們查看 HTTP 會話超時配置。
這一工具提供的兩種主要分析功能是:
單一轉儲分析最經常與內存轉儲一起使用,它們由 IBM Developer Kit、帶有 OutOfMemoryExceptions 異常的Java Technology Edition 自動觸發。這一分析類型使用啟發式進程來確定受懷疑的數據結構,這些數據結構擁有一個帶有大量子對象的容器對象。這一啟發式進程對于檢測泄漏 Java 集合對象非常有效,這些對象使用一個內部數組來存儲所包含的對象。在大量由 IBM Support 處理的內存泄漏案例中,已經發現這一啟發式進程非常有效。
比較分析用于比較兩個在一次運行內存泄漏應用程序期間(也就是當自由 Java 堆內存減少時)所取得的兩個內存轉儲(主轉儲和基線轉儲)。比較分析非常適合與輕量級內存泄漏檢測一起使用。對于比較分析,主轉儲表示在已經發生大量內存泄漏時(占用最大配置堆大小的大量內存)所取得轉儲?;€轉儲是指當堆尚未因內存泄漏而被大量耗用時早期取得的堆轉儲。這兩個轉儲之間的堆耗用越大,分析結果就越好。
比較分析技術確定一組大規模數據結構,它們在許多組成數據類型的實例數目方面快速增長。數據結構被分組到每個轉儲中,然后在主轉儲和基線轉儲之間進行匹配與比較,以確定大量增長的可疑數據結構。這一技術不同于當今市場上許多分析工具中可用的基本堆轉儲區分技術,差別在于,這一技術在更高級別的粒度標識可疑泄漏數據結構,而不是標識泄漏數據類型(例如,粒度級別低很多的字符串)。例如,MDD4J 將告訴您,一個具體容器(例如特定的 EJB 對象)正在泄漏大量字符串,而不是簡單地告訴您正在從某一未知源泄漏大量字符串。標識可疑數據結構有助于更好地理解內存泄漏的根源。在圖 3 中的樹視圖中描述了一種示例數據結構,在其中不僅可能看到正在泄漏的字符串對象,而且可以看出它們正被 MyClass 類中的 HashSet引用。
分析結構顯示在基于 Web 的交互式用戶界面中,其具有以下特性:
列出分析結果、堆內容、大小和發展的摘要。
列出導致堆使用增長的可疑數據結構、數據類型和數據包,用于比較分析;列出大規模堆,用于單一傳儲分析。
所屬權上下文視圖顯示內存占用空間的主要貢獻者與主要內存占用空間貢獻者摘要集合的主要組成數據類型之間的所屬關系。
交互式樹視圖中的瀏覽功能顯示了堆轉儲的相關部分,顯示對于堆中所有可疑容器對象和該容器對象之所有子對象的所有傳入(僅一個顯示于樹中的引用,其余引用分別顯示)和傳出引用,它們根據到達大小排序。
從可疑列表到所屬權上下文和從內容視圖再到瀏覽視圖的導航功能。
內存轉儲中所有對象和數據類型的表格式視圖,帶有篩選器和有序列。
MDD4J 工具將來自許多現有工具的最佳特性組合在一起。比較分析技術基于 Leakbot 研究項目(請參見參考資料)。單一轉儲分析特性使用的分析技術也可以在 HeapAnalyzer 工具中找到,此工具可以從 alphaWorks 下載(請參見參考資料)。表格式視圖基于來自一種命令行工具 HeapRoots 的特性(請參見參考資料)。
使用 WebSphere Application Server V6.1,可以將用于 Java 工具的 Memory Dump Diagnostic (版本 1.0)與 IBM Support Assistant 工具(版本 3.0)一起打包,這是一種獨立于 WebSpherer Application Server 單獨安裝的系統管理員獨立工具(請參見參考資料),該工具可以安裝在任何計算機上,只要可以將堆轉儲轉換到該計算機上進行脫機分析即可。(有關如何從 Support Assistant 3.0 版 啟動 MDD4J 1.0 版的信息,請參見參考資料。)
在下載 IBM Support Assistant 之后,可以利用 Updater 機制單獨添加 Memory Dump Diagnostic for Java:在 IBM Support Assistant 中,選擇Updater 視圖中的 New Products and Tools => Common Component and Tools(還請確保已經安裝了 WebSphere Application Server V6.0 或 V5.0 產品插件)。
相對于以前版本(版本 0.97a),MDD4J(版本 1.0)的這一新版本的特性具有許多與可伸縮性有關的改進,并且支持 64 位堆轉儲。(MDD4J 的這一先前版本可以作為技術預覽 developerWorks 下載,請參見參考資料。)
下面的示例顯示了對于簡單內存泄漏 Java 應用程序的內存泄漏分析結果。這一示例應用程序將字符串對象泄漏到一個靜態 HashMap 中。輕量級泄漏檢測能夠確定早期泄漏的出現,并自動產生適當的堆轉儲。然后,使用 Memory Dump Diagnostic for Java Version 1.0 中的比較分析對這些轉儲進行脫機分析。顯示內存泄漏疑點的分析結構顯示在圖 2、圖 3 和圖 4 中。
圖 3. 在 Memory Dump Diagnostic for Java 中瀏覽可疑數據結構
圖 4. Memory Dump Diagnostic for Java 分析的內存占用空間分析
結束語
使用 WebSphere Application Server V6.1,系統管理員能夠在其生產環境中接收關于內存泄漏的早期通知,而不必使用字節代碼插入或任何附加代理。已經設計了輕量級內存泄漏檢測,其可以將對性能的影響降至最低,并提供在適當時間自動生成堆轉儲的功能,以確保正確的分析結果。
可以使用 Memory Dump Diagnostic for Java (MDD4J) 以脫機方式分析手動生成或者在內存泄漏檢測的幫助下生成的堆轉儲。這一工具可以幫助系統管理員將問題限制到到適當的組件,開發人員可以在其計算機上很容易地重現分析結果。MDD4J 為開發人員和問題檢測顧問提供了一種工具,用以確定泄漏懷疑對象,瀏覽堆和所屬權鏈,以確定其代碼中的什么數據結構正在泄漏。
這一技術非常有助于診斷 Java 堆內存泄漏并對其進行分析,既可用于良好的系統測試過程,也可用于生產系統。
![]() ![]() |
![]()
|
致謝
本文作者向以下各位表示感謝:感謝 Daniel Julin 和 Stan Cox 審閱本文;感謝 LeakBot 項目的首席研究員 Nick Mitchell 的領導和創新;感謝 Mark T Schleusner 在開發 MDD4J 過程中的幫助和協作。
原文轉自:http://www.anti-gravitydesign.com