深度探索JFR - JFR詳細介紹與生產問題定位落地 - 2. 通過一個線上調優例子瞭解JMC 與 Event 結構與詳細配置

查看 JFR 事件的工具 - JMC (Java Mission Control)

官網地址:https://adoptopenjdk.net/jmc.html

國內下載起來比較慢,建議在aws上面建一個歐洲法蘭克福的實例,在這個實例上先下載好,然後傳輸到本地。或者直接用我下面提供的連接下載,我也會跟着官網上面的版本進行更新的。

我的私人下載地址:https://zhxhash-blog.oss-cn-beijing.aliyuncs.com/resources/jmc.zip

如果更新的不夠及時,歡迎大家留言提醒我要更新啦。謝謝

首先打開 jmc,我們通過 “文件” -> “打開文件” 來打開一個 jfr 文件。 由於 JFR 文件裏面的數據要全部導入內存,而且 JMC 需要給這些數據做很多索引以及報表,最後的內存佔用大概是原始文件的4~6倍左右。如果你的系統內存不足, JMC 也會提示你只截取一部分查看。最好你在 dump JFR 文件的時候,就利用 begin 還有 end 參數截取你感興趣的時間段。

打開文件後, JMC 會自動對事件進行歸類和分析,出一些報表出來。有些分析和建議非常有用,可以參考,報表也比事件更加直觀。

但是就我個人使用傾向來看,我還是喜歡直接去看事件瀏覽器裏面的具體事件。

我們先用一個簡單的線上調優的例子,來初步瞭解下 JFR 的使用。

JVM 調優簡單實例

線上某個實例,dump出了 jfr 文件。下載到本地,按照持續時間倒序查看 GC Event:

在這裏插入圖片描述

發現有一些耗時比較高的 GC 事件, 並且這些事件都是 Old GC。GC 原因是:G1 Humongous Allocation。

大型對象(Humongous)是大於 G1 中 region 大小50%的對象。頻繁大型對象分配會導致性能問題。如果 region 裏面包含大量的大型對象,則該region中最後一個具有巨型對象的區域與區域末端之間的空間將不會使用。如果有多個這樣的大型對象,這個未使用的空間可能導致堆碎片化。針對這個原因,調整的方法一般是修改 region 的大小是這個 大對象的 2 倍以上。那麼這個大對象有多大呢?

我們可以通過 Old Object Sample 這個 Event 來查看老對象採樣,一般隨着你的程序運行時間增長,這個採集會更加準確地命中到你最關注的對象。

在這裏插入圖片描述

注意這個 Event 裏面的 heap used 不是這個對象用的堆大小,而是當前所有對象佔用的堆內存大小。這個對象大小,可以通過數組大小計算而出,這裏最大就是 3.31 * 10^6 字節

我們再來看一下當前 G1HeapRegionSize 的配置,通過查看 Unsiged Long Flag Event:

在這裏插入圖片描述

發現大小是:4.19 * 10^6 字節,不足最大對象的兩倍。所以,這裏我們需要將 G1HeapRegionSize 至少調整到 6.62 * 10^6 字節

調整 G1HeapRegionSize 之後,不再出現 G1Old GC。

Event 數據結構以及配置結構

這裏再提一下 Event 的結構,每個 Event 都會包括:

  • Event 大小
  • Event ID
  • Event 產生的時間戳
  • Event 持續時間
  • 產生Event的線程 ID
  • 相關 堆棧 ID

除了這些元素,每個 Event 還會有自己的 Payload,承載自己要採集的數據。但是注意一點,不是每個Event都會填充上面的這些字段,只是結構裏面有這些字段,但是可能並不會採集。

Event採集,同樣有以下這些公共配置:

  • enabled,是否啓用這個 Event 的採集:true 或者 false
  • cutoff:截斷,採集多長時間以內的這種 Event,支持單位配置,例如1d, 1h, 1m, 1s, 1ms, 1ns,配置爲0則不截斷
  • stackTrace,是否啓用堆棧跟蹤:true 或者 false
  • period,採集週期(時段):beginChunk(每個 Data Chunk 的開頭,在每一個 Data Chunk 寫滿另起一個的時候,立刻採集一次),everyChunk(每個 Data Chunk 的,在每一個 Data Chunk 寫到佔用一半空間限制的時候,立刻採集一次),endChunk(每個 Data Chunk 的結束,在每一個 Data Chunk 寫滿,立刻採集一次),或者配置具體時間,支持單位配置,例如1d, 1h, 1m, 1s, 1ms, 1ns;對於 Data Chunk 的解釋,請參考上一節。
  • threshold,閾值:Event 持續時間超過這個閾值纔會採集,支持單位配置,例如1d, 1h, 1m, 1s, 1ms, 1ns

Event採集詳細配置, JDK自帶兩個模板,在 $JAVA_HOME/lib/jfr 目錄下,裏面配置格式是一個xml文件,取其中一個配置舉個例子,例如:

  <event name="jdk.OldObjectSample">
    <setting name="enabled" control="memory-leak-detection-enabled">true</setting>
    <setting name="stackTrace" control="memory-leak-detection-stack-trace">false</setting>
    <setting name="cutoff" control="memory-leak-detection-cutoff">0 ns</setting>
  </event>

這個就是 OldObject 採集 Event 的配置,這裏配置爲啓用這個採集,不採集堆棧,不截斷。你也可以加上 period 和 threshold 配置,但對這個 Event 沒啥效果就是了。這裏有個 control 屬性,接下來會提到。

我們一般通過 JMC 來配置這些 jfr 文件。打開 窗口->飛行記錄模板管理器,將 default.jfc 和 profile.jfc 導入進去,我們來看下 default.jfc。點擊編輯,彈出一個快速編輯模板,這裏不會配置每一個具體 Event,而是在整體上讓你快速配置。這個配置,是基於 default.jfc 裏面的 selection 標籤還有 condition 標籤。舉個例子:

在這裏插入圖片描述

這裏配置的 Memory Leak Detection 對應其中 Memory Leak Detection 的 selection 標籤,可選項有四個,只有 memory-leak-detection 爲 off 的時候,memory-leak-detection-enabled 爲 false, 這樣 OldObjectSample 的 enabled 就爲 false,因爲 enable 的 control 屬性是 memory-leak-detection-enabled。

這就是可以比較籠統的配置的原理。點擊 高級,會跳轉到所有 Event 的具體配置。在接下來的章節,我們來講一下所有 Event 的採集詳細配置。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章