1. 程式人生 > >Java多執行緒--使用Java Mission Control進行記憶體分配分析

Java多執行緒--使用Java Mission Control進行記憶體分配分析

jdk7u40自帶了一個非常好用的工具,就是Java Mission ControlJRockit Misson Control使用者應該會對mission control的很多功能十分熟悉,JRockit也是一款很棒的工具。本篇文章將著重關注如何使用Java Flight Recorder進行記憶體分配分析。

jvm有著非常棒的小塊記憶體虛擬化技術,這會讓你產生一種擁有無限記憶體的錯覺感,其實它的開銷非常大。有時候jvm需要找出此刻堆上資料是如何被使用的,並把剩餘的空間擴大——這就是垃圾回收。產生這種情況的原因是,jvm實際獲得的實體記憶體是有限的,因此需要在不被使用時進行記憶體回收和複用。在一些時間敏感的應用中,比如交易系統和通訊程式,這些暫停是不能容忍的。有很多GC調優方法可以避免這種暫停發生。貌似上面的討論已經跑題了。讓GC變少的方法當然是儘量減少分配記憶體。

有時候,你希望找出在你的程式中哪些地方導致了記憶體分配的壓力。引起這種壓力的原因有很多種。最普通的一種情況可能是jvm需要經常GC,並且時間遠超過你認為的合理值。

JFR分配事件

在HotSpot7u40中實現的Java Flight Recorder(JFR)有兩種記憶體分配事件可以幫助我們找出程式中進行記憶體分配的地方:TLAB中的記憶體分配和TLAB外的記憶體分配事件。

與JDK提供的其它大多數事件相類似,有一系列可在Mission Control中進行定製的分析介面。在進行分析之前,我們要花上幾分鐘來討論下實際的事件。

首先,你需要確保事件已近被記錄了。如果你使用預設的模板選項,你會發現記憶體分配分析選項預設是關閉的。要麼開啟它,或者使用分析模板而不要使用預設模板。記憶體分析選項預設關閉的原因是,它可能會產生太多的事件。並且對於不同的程式它的效能消耗是不確定的,因為不同的程式在記憶體分配的情況上是差別是很大的。

事件標籤組中的Log標籤是檢視每個單獨事件的絕佳地址。我們來看看這裡包括了哪些內容:

這裡包括已經分配的記憶體確切大小、導致記憶體分配的堆疊軌跡、分配記憶體的類和事件資訊。在TLAB記憶體分配事件中,它們還包括分配的TLAB大小。

需要注意的是,TLAB的記憶體分配事件中並不是對應每一個地點的記憶體分配事件,那樣太消耗資源了。取而代之的是,我們只在新的TLAB中第一次分配記憶體時進行事件上報。這意味著我們只獲得了本地執行緒的記憶體分配一些排序後的樣本。

此外,需要注意的是我們在JRockit中使用的TLA事件和在新生代中進行的分配是完全相同的,大物件分配事件和老生代記憶體分配時相同的。不過這些在HotSpot中有點複雜。TLAB外的記憶體分配事件既可以和年輕代記憶體回收分配相同,也可以和後續的Eden區及old區域的直接大物件分配相同。換句話說,如果你在TLAB事件外發現了一些少量的記憶體分配,你並不需要擔心。正常來說,這種情況是非常的少見的。因此在實際情況中這些區分並不是那麼明顯。

使用Allocation標籤頁

Allocation(分配)標籤頁實際上包含三個子標籤頁:

  1. 通用
  2. 新TLAB分配
  3. TLAB外分配

通用標籤頁提供了一個總的檢視和一些可用事件的統計資訊,例如對於不同的事件型別分配的總記憶體。依據你首要目標的不同,對待這些資訊的方式也會不同。下面的這個例子十分精簡併且聚焦在內部TLAB分配,因為它更關注於總的記憶體分配壓力。

新TLAB分配提供了三種以上專供於分析新TLAB分配事件的虛擬化型別:類級、執行緒級和分析級的分配。分析級分配是對這三種類型的一個簡單的棧追蹤集合。從下面的這個例子可以看出,Integer物件幾乎佔到整個系統的所有記憶體分配。在直方圖中選擇Integer類便會顯示出對Integer物件的所有記憶體的棧軌跡集合,同時在這個例子中,所有的分配都來自同一個地點,正如下圖展示的那樣。

TLAB外分配的記憶體標籤頁和新TLAB標籤頁的工作原理相同,僅僅在這個時間點是一致的,當然這些是TLAB外的事件。

限制

因為新TLAB的記憶體分配事件僅僅只是總的執行緒本地記憶體分配的樣本,僅僅只有一個事件是很難說明實際情況的。更多的事件才會有更精確的圖片。此外,如果分配事件的行為在記錄期間變化非常大,那麼這樣也很難建立一個十分有說服力本地記憶體分配檢視。

原文連結: hirt 翻譯: ImportNew.com 潘 凌霄
譯文連結: http://www.importnew.com/13346.html
轉載請保留原文出處、譯者和譯文連結。]