1. 程式人生 > >【開發工具】JAVA效能分析:7、超詳細的JProfiler堆分析(官方中文版)

【開發工具】JAVA效能分析:7、超詳細的JProfiler堆分析(官方中文版)

堆分析——The Heap Walker

一、堆快照——Heap snapshots

涉及物件之間引用的任何堆分析都需要堆快照,因為無法向JVM詢問對物件的傳入引用是什麼 - 您必須遍歷整個堆來回答該問題。從該堆快照,JProfiler建立一個內部資料庫,該資料庫經過優化,可以生成在堆walker中提供檢視所需的資料。

堆快照有兩個來源:JProfiler堆快照和HPROF堆快照。JProfiler堆快照支援堆walker中的所有可用功能。概要分析代理使用概要分析介面JVMTI迭代所有引用。如果配置檔案JVM在另一臺計算機上執行,​​則所有資訊都將傳輸到本地計算機,並在那裡執行進一步的計算。HPROF快照是使用JVM中的內建機制建立的,並以JProfiler可以讀取的標準格式寫入磁碟。

在堆walker的概述頁面上,您可以選擇是否應建立JProfiler堆快照或HPROF堆快照。預設情況下,建議使用JProfiler堆快照。HPROF堆快照在另一章中討論的特殊情況下非常有用。

二、選擇步驟——Selection steps

堆walker由幾個檢視組成,這些檢視顯示所選物件集的不同方面。在獲取堆快照之後,您正在檢視堆上的所有物件。每個檢視都有導航操作,用於將某些選定物件轉換為當前物件集。堆walker的標題區域顯示有關當前物件集中包含的物件數的資訊。

最初,您正在檢視“類”檢視,該檢視類似於實時記憶體部分中的“所有物件”檢視 。通過選擇一個類並呼叫 Use-> Selected Instances

,可以建立一個僅包含該類例項的新物件集。在堆walker中,“using”始終意味著建立一個新的物件集。

對於新的物件集,顯示堆walker的classes檢視不會很有趣,因為它實際上只是將表過濾到先前選擇的類。相反,JProfiler使用“新建物件集”對話方塊建議另一個檢視。您可以取消此對話方塊以放棄新物件集並返回上一個檢視。建議使用傳出引用檢視,但您也可以選擇其他檢視。這僅適用於最初顯示的檢視,之後您可以在堆walker的檢視選擇器中切換檢視。

標題區域現在告訴您有兩個選擇步驟,包括用於計算保留和深度大小的連結或用於使用當前物件集保留的所有物件的連結。後者將新增另一個選擇步驟並建議類檢視,因為該物件集中可能存在多個類。

在堆步行器的下半部分,列出了到此為止的選擇步驟。單擊超連結將返回任何選擇步驟。也可以使用工具欄中的“ 轉到開始”按鈕訪問第一個資料集 。如果需要在分析中回溯,工具欄中的後退和前進按鈕非常有用。

三、類檢視——Classes view

堆walker頂部的檢視選擇器包含五個檢視,顯示當前物件集的不同資訊。第一個是“類”檢視。

類檢視類似於實時記憶體部分中的“所有物件”檢視,並且具有可以將類分組到包中的聚合級別選擇器。此外,它還可以顯示課程的估計保留大小。這是從堆中刪除所有類的例項時將釋放的記憶體量。如果單擊“ 計算估計保留大小”超連結,則會新增新的“ 保留大小”列。顯示的保留大小是估計的下限,計算確切的數字會太慢。如果您確實需要確切的數字,請選擇感興趣的類或包,並使用 新物件集標題中的計算保留和深度大小超連結。

根據您選擇的一個或多個類或包,您可以選擇例項本身,關聯java.lang.Class物件或所有保留物件。雙擊是最快的選擇模式,並使用選定的例項。如果有多種選擇模式可用,則在此情況下,檢視上方會顯示“ 使用”下拉選單。

解決與類載入器相關的問題時,通常必須按類載入器對例項進行分組。“ 檢查”選項卡提供了“按類載入器分組”檢查,該檢查在類檢視中可用,因為它在該上下文中尤為重要。如果執行該分析,則頂部的分組表將顯示所有類載入器。選擇類載入器會在下面的檢視中相應地過濾資料。當您切換到堆walker的其他檢視時,分組表將保持不變,直到您執行另一個選擇步驟。然後,類載入器選擇成為該選擇步驟的一部分。

四、分配錄製檢視——Allocation recording views

在縮小記憶體洩漏的嫌疑人或嘗試減少記憶體消耗時,分配物件的資訊可能很重要。對於JProfiler堆快照,“分配”檢視顯示分配呼叫樹以及已記錄分配的那些物件的分配熱點。其他物件在分配呼叫樹中的“未記錄物件”節點中分組。對於HPROF快照,此檢視不可用。

與在類檢視中一樣,您可以選擇多個節點並使用頂部的“ 使用所選項”按鈕建立新的選擇步驟。在“分配熱點”檢視模式下,您還可以選擇後面跟蹤中的節點。這將僅選擇在以所選回溯跟蹤結束的呼叫堆疊上分配的關聯頂級熱點中的物件。

JProfiler在記錄分配時可以儲存的另一條資訊是分配物件的時間。堆walker中的“Time”檢視顯示當前物件集中所有記錄例項的分配時間的直方圖。您可以單擊並拖動以選擇一個或多個間隔,然後使用“ 使用所選項”按鈕建立新的物件集。

要更精確地選擇時間間隔,您可以指定一系列 書籤。然後將標記第一個和最後一個所選書籤之間的所有物件。

除時間檢視外,分配時間在參考檢視中顯示為單獨的列。但是,預設情況下不啟用分配時間記錄。您可以在時間檢視中直接開啟它,也可以編輯配置檔案設定對話方塊的“ 記憶體配置檔案”選項卡上的設定。

五、最大的物件檢視——Biggest objects view

最大的物件檢視顯示當前物件集中最重要的物件的列表。此上下文中的“Biggest”表示如果從堆中刪除它們將釋放大多數記憶體的物件。該大小稱為保留大小。相反,深度大小是通過強引用可到達的所有物件的總大小。

可以展開每個物件以顯示對此物件保留的其他物件的傳出引用。通過這種方式,您可以遞迴地展開保留物件的樹,如果要移除其中一個祖先,這些樹將被垃圾收集。這種樹被稱為“支配樹”。此樹中為每個物件顯示的資訊類似於傳出參考檢視,只是顯示了僅限制的引用。

並非所有支配物件都被其支配者直接引用。例如,請考慮下圖中的引用:

物件A支配物件B1和B2,並且它沒有物件C的直接引用.B1和B2都引用C.B1和B2都不支配C,但A支配。在這種情況下,B1,B2和C在支配樹中被列為A的直接子節點,而C不會被列為B1和B2的子節點。對於B1和B2,顯示它們所在的A中的欄位名稱。對於C,“[傳遞參考]”顯示在參考節點上。

在支配樹中每個參考節點的左側,大小條顯示目標物件仍保留頂級物件的保留大小的百分比。當您深入到樹中時,數字會減少。在檢視設定中,您可以將百分比基數更改為總堆大小。

支配樹具有內建截斷,消除了保留大小低於父物件保留大小0.5%的所有物件。這是為了避免過多的小型主導物件列表,這些物件會分散對重要物件的注意力。如果發生這樣的截止,將顯示一個特殊的“cutoff”子節點,通知您有關此級別上未顯示的物件數,它們的總保留大小以及單個物件的最大保留大小。

主導樹也可以將最大的物件分組到類中,而不是顯示單個物件。檢視頂部的分組下拉列表包含一個啟用此顯示模式的複選框。此外,您可以在頂層新增類載入器分組。在計算最大物件之後應用類載入器分組,並顯示誰載入了最大物件的類。如果要分析一個特定類載入器的最大物件,可以先使用“按類載入器分組”檢查。

最大物件檢視上方的檢視模式選擇器允許您切換到備用視覺化:樹圖,將所有支配物件顯示為一組巢狀矩形。

在樹形圖中,每個矩形表示一個主導物件,其面積與其保留大小成比例。與樹形成對比,樹形圖為您提供了支配樹中所有葉子的平面透檢視。如果您對大陣列感興趣,可以使用樹形圖快速找到它們,而無需深入挖掘樹的分支。此外,樹形圖可以讓您全面瞭解支配物件的相對重要性以及堆上的物件大小分佈。

在樹形圖的右下角,您可以看到樹對映表示的整個堆的總百分比。如果尚未放大,則由於保留大小的內部閾值,堆的剩餘部分由未進入最大物件列表的物件控制。

六、參考檢視——Reference views

與之前的檢視不同,僅當您執行了至少一個選擇步驟時,參考檢視才可用。對於初始物件集,這些檢視沒有用,因為傳入和傳出的引用檢視顯示所有單個物件,並且合併的引用檢視只能針對一組焦點物件進行解釋。

傳出引用檢視類似於偵錯程式在IDE中顯示的檢視。開啟物件時,您可以看到原始資料和對其他物件的引用。可以選擇任何引用型別作為新物件集,並且可以一次選擇多個物件。與在類檢視中一樣,您可以選擇保留的物件或關聯的java.lang.Class物件。如果所選物件是標準集合,則還可以通過單個操作選擇所有包含的元素。對於類裝入器物件,可以選擇所有已載入的例項。

預設情況下不顯示具有空引用的欄位,因為該資訊可能會分散記憶體分析的注意力。如果要檢視所有欄位以進行除錯,可以在檢視設定中更改此行為。

除了簡單選擇顯示的例項外,傳出引用檢視還具有 強大的過濾功能。對於實時會話,傳出和傳入參考檢視都具有高階操作和顯示功能,這將在同一章中討論。

傳入引用檢視是解決記憶體洩漏的主要工具。要找出物件未被垃圾收集的原因,“ 顯示路徑到GC根”按鈕將找到垃圾收集器根的參考鏈。關於記憶體洩漏的章節有關於這個重要主題的詳細資訊。

七、合併參考——Merged references

檢查許多不同物件的引用可能很繁瑣,因此JProfiler可以向您顯示當前物件集中所有物件的合併傳出和傳入引用。預設情況下,引用按類聚合。如果類的例項由同一個類的其他例項引用, 則會插入一個特殊節點,該 節點顯示原始例項以及這些類遞迴引用中的例項。此機制會自動摺疊常見資料結構中的內部引用鏈,例如連結列表中的內部引用鏈。

您還可以選擇顯示按欄位分組的合併參考。在這種情況下,每個節點都是引用型別,例如類的特定欄位或陣列的內容。對於標準集合,會破壞累積的內部引用鏈,因此您會看到引用型別,如“java.lang.HashMap的對映值”。與類聚合不同,此機制僅適用於來自JRE標準庫的顯式支援的集合。

在“合併的傳出引用”檢視中,例項計數引用引用的物件。在“合併傳入引用”檢視中,您會在每行上看到兩個例項計數。第一個例項計數顯示沿此路徑引用當前物件集中的例項數。節點左側的條形圖示視覺化此分數。箭頭圖示指向儲存對父節點的引用的物件後的第二個例項計數。執行選擇步驟時,您可以選擇是否要從當前物件集中選擇以所選方式引用的物件,或者您是否對具有所選引用的物件感興趣 - 引用持有者。

使用“Merged dominating references”檢視,您可以找出必須刪除哪些引用,以便可以對當前物件集中的部分或全部物件進行垃圾回收。主導參考樹可以被解釋為最大物件檢視中的支配樹的合併逆,為類聚合。參考箭頭可能不表示兩個類之間的直接引用,但是其間可能存在其他類,其中包含非支配引用。在多個垃圾收集器根的情況下,當前物件集中的一些或所有物件可能不存在主導引用。

預設情況下,“Merged dominating references”檢視顯示傳入的主導引用,通過開啟樹,您可以訪問GC根保留的物件。有時,參考樹可能會沿著許多不同的路徑導致相同的根物件。通過在檢視頂部的下拉列表中選擇“GC根到物件”檢視模式,您可以看到反向透檢視,其中根位於頂層,而當前物件集中的物件位於葉節點中。在這種情況下,引用從頂層到葉節點。哪個視角更好取決於您要消除的引用是接近當前物件集還是接近GC根。

八、檢查——Inspections

“檢查”檢視本身不顯示資料。它提供了許多堆分析,這些分析根據其他檢視中不可用的規則建立新物件集。例如,您可能希望檢視本地執行緒保留的所有物件。這在參考檢視中是不可能的。檢查分為幾類,並在其說明中進行了解釋。

檢查可以將計算出的物件集劃分為組。組顯示在堆walker頂部的表中。例如,“重複字串”檢查將重複的字串值顯示為組。如果您在參考檢視中,則可以在java.lang.String下面看到具有所選字串值的例項。最初,選擇組表中的第一行。通過更改選擇,可以更改當前物件集。組表的“ 例項計數”和“ 大小”列會告訴您選擇行時當前物件集的大小。

組選擇不是堆步行器中的單獨選擇步驟,但它成為檢查所做選擇步驟的一部分。您可以在底部的選擇步驟窗格中檢視組選擇。更改組選擇時,將立即更新選擇步驟窗格。

每個建立組的檢查決定哪些組在檢查的上下文中最重要。由於這並不總是對應於其他列之一的自然排序順序, 因此組表中的“ 優先順序”列包含一個數值,用於強制執行檢查的排序順序。

對於大堆計算,檢查可能很昂貴,因此結果會被快取。通過這種方式,您可以返回歷史記錄並檢視先前計算的檢查結果,而無需等待。

九、堆沃克圖——Heap walker graph

例項的最真實表示及其引用是一個圖表。雖然圖形具有低視覺密度並且對於某些型別的分析是不切實際的,但它仍然是視覺化物件之間關係的最佳方式。例如,迴圈引用很難在樹中解釋,但在圖中很明顯。此外,將傳入和傳出的引用放在一起可能是有益的,這在樹結構中是不可能的,在樹結構中您可以看到其中一個或另一個。

堆walker圖不會自動顯示當前物件集中的任何物件,也不會在更改當前物件集時清除它。通過選擇一個或多個例項並使用“ 在圖形中顯示”操作,可以從傳出引用檢視,傳入引用檢視或最大物件檢視中手動將所選物件新增到圖形中

預設情況下,圖表中的包名稱會縮短。與CPU呼叫圖一樣,您可以在檢視設定中啟用完整顯示。參考文獻被繪製為箭頭。如果將滑鼠移到參考上,將顯示工具提示視窗,其中顯示特定參考的詳細資訊。從參考檢視手動新增的例項具有藍色背景。最近添加了一個例項,背景顏色越深。垃圾收集器根有紅色背景,類有黃色背景。

預設情況下,參考圖僅顯示當前例項的直接傳入和傳出引用。您可以通過雙擊任何物件來展開圖形。這將擴充套件該物件的直接傳入或直接傳出引用,具體取決於您移動的方向。通過例項左側和右側的擴充套件控制元件,您可以選擇性地開啟傳入和傳出引用。如果您需要回溯,請使用撤消功能恢復圖形的先前狀態,這樣您就不會被太多節點分心。要修剪圖形,可以刪除所有未連線的節點,甚至刪除所有物件。

與傳入引用檢視一樣,該圖具有“ 顯示路徑到GC根”按鈕,該按鈕將一個或多個引用鏈擴充套件到垃圾收集器根( 如果可用)。此外,如果選擇了兩個例項,則“ 兩個選定節點之間查詢路徑”操作處於活動狀態。它可以搜尋有向和無向路徑,也可以選擇沿弱引用。如果找到合適的路徑,則以紅色顯示。

十、初始物件集——Initial object set

獲取堆快照時,可以指定控制初始物件集的選項。如果已記錄分配,則“ 選擇記錄的物件”複選框會將最初顯示的物件限制為已記錄的物件。這些數字通常與實時記憶體檢視中的數字不同,因為堆疊walker會刪除未引用的物件。堆疊快照中仍存在未記錄的物件,它們不會顯示在初始物件集中。通過進一步的選擇步驟,您可以訪問未記錄的物件。

此外,堆walker執行垃圾收集並刪除弱引用的物件,軟引用除外。這通常是可取的,因為在查詢僅有強引用物件相關的記憶體洩漏時,弱引用的物件會分散注意力。但是,在您對弱引用物件感興趣的情況下,您可以告訴堆walker保留它們。JVM中的四個弱引用型別是“軟”,“弱”,“幻像”和“終結器”,您可以選擇其中哪些應足以在堆快照中保留物件。

如果存在,可以使用堆步行器中的“弱引用”檢查從當前物件集中選擇或刪除弱引用的物件。

十一、標記堆——Marking the heap

通常,您希望檢視為特定用例分配的物件。雖然您可以通過啟動和停止圍繞該用例的分配記錄來實現此目的,但有一種更好的方法可以減少開銷並保留分配記錄功能用於其他目的:在堆步行器概述上公佈的Mark Heap操作這也可以在“效能分析” 選單中使用,或者作為觸發器操作將堆上的所有物件標記為“舊”。當您獲取下一個堆快照時,現在可以清楚“新”物件應該是什麼。

如果存在先前的堆快照或標記堆呼叫,堆walker的標題區域將顯示新的例項計數和兩個標題為Use newUse old的連結,這些連結允許您選擇自該點以來已分配的例項。時間,或之前分配的倖存例項。此資訊可用於每個物件集,因此您可以先向下鑽取並稍後選擇新的或舊的例項。