摘要:java內存dump是jvm運行時內存的一份快照,利用它能夠分析是否存在內存浪費,能夠檢查內存管理是否合理,當發生OOM的時候,能夠找出問題的緣由。那麼dump文件的內容是什麼樣的呢?
java內存dump是jvm運行時內存的一份快照,利用它能夠分析是否存在內存浪費,能夠檢查內存管理是否合理,當發生OOM的時候,能夠找出問題的緣由。那麼dump文件的內容是什麼樣的呢?咱們一步一步來java
獲取dump文件的方式分爲主動和被動程序員
i.主動方式:
1.利用jmap,也是最經常使用的方式:jmap -dump:[live],format=b,file=
2.利用jcmd,jcmd GC.heap_dump
3.使用VisualVM,能夠界面操做進行dump內存
4.經過JMX的方式web
MBeanServer server = ManagementFactory.getPlatformMBeanServer(); HotSpotDiagnosticMXBean mxBean = ManagementFactory.newPlatformMXBeanProxy(server, "com.sun.management:type=HotSpotDiagnostic", HotSpotDiagnosticMXBean.class); mxBean.dumpHeap(filePath, live);
參考(https://www.baeldung.com/java...segmentfault
ii.被動方式:
被動方式就是咱們一般的OOM事件了,經過設置參數-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=數組
結構示意圖瀏覽器
結構詳解dom
dump文件是堆內存的映射,由文件頭和一系列內容塊組成jvm
文件頭ide
由musk, 版本,identifierSize, 時間4部分組成工具
一、musk:4個byte,內容爲'J', 'A', 'V', 'A'即JAVA
二、version:若干byte,值有如下三種
" PROFILE 1.0\0", " PROFILE 1.0.1\0", " PROFILE 1.0.2\0"
三、identifierSize:4個byte數字,值爲4或者8,表示一個引用所佔用的byte數
四、time:8個byte,dump文件生成時間
說明:java一個類的成員變量有兩種類型
public class Person { private int age;//4個byte private String name;//identifierSize個byte private double weight;//8個byte }
當咱們在new Person()的時候
它就須要申請一個空間,空間大小爲 對象頭大小+4+identifierSize+8個byte
對象大小的測量:
jdk提供一個測試對象佔用內存大小的工具Instrumentation,可是Instrumentation無法直接引用到,須要經過agent來引用到
定義一個Premain類, javac Premain.java
//Premain.java public class Premain { public static java.lang.instrument.Instrumentation inst; public static void premain(String args, java.lang.instrument.Instrumentation inst) { Premain.inst = inst; } }
編寫一個Manifest文件
manifest.mf Manifest-Version: 1.0 Premain-Class: Premain Can-Redefine-Classes: true Can-Retransform-Classes: true
打包
jar -cmf manifest.mf premain.jar Premain.class
定義一個執行類, javac PersonTest.java
//PersonTest.java public class PersonTest { public static void main(String[] args) throws Exception { Class clazz = Class.forName("Premain"); if (clazz != null) { Person p = new Person(); java.lang.instrument.Instrumentation inst = (java.lang.instrument.Instrumentation)clazz.getDeclaredField("inst").get(null); System.out.println("person size:[" + inst.getObjectSize(p) + "]B"); System.out.println("class size:[" + inst.getObjectSize(p.getClass()) + "]B"); } } }
帶agent執行
java -javaagent:premain.jar PersonTest
結果:
person size:[32]B class size:[504]B
每一個塊都是塊頭和塊體組成
塊頭
塊頭由1個byte的塊類型,4個byte的時間time,4個byte的長度表示此內容塊佔用byte數
type類型通常有5種,字符串,類,棧楨,棧,及dump塊
gc root
gc root有4種結構,8種類型
gc root示意圖
gc root爲垃圾收集追溯的源頭,每一個gc root都指向一個初始對象,沒法追溯的對象是要被回收掉的
系統類,只有classLoader爲null的類纔是gc root,每一個類都是一個gc root
線程棧,線程中方法參數,局部變量都是gc root,每一個對象都是一個gc root
系統保留對象,每一個對象都是一個gc root
一、基本信息:
二、說明:
(1)類裏面的常量不少地方都沒有用上,因此常量個數通常爲0
(2)類的靜態變量的名稱類型及值是放在類對象裏面的,成員變量的名稱和類型也是放在類對象裏面的,可是實例的值是放在實例對象裏面的
實例對象
一、基本信息:
二、說明:
一、基本信息:
二、說明:
對象數組
一、基本信息:
當一個線程啓動的時候,進程會去系統內存生成一個線程棧
每當發生一次方法調用,就會向棧中壓入一個棧楨,當方法調用完以後,棧楨會退出
在運行過程當中,若是有對象的new操做的時候,進程會去堆區申請一塊內存
關於運行時內存的詳細狀況,能夠查找相關的資料
若是一個對象不能騎過gc root引用可達,那麼這個對象就可能要被回收
對象回收規則包括
public void test(){ Object a = new Object();//obj 1 Object b = new Object();//obj 2 { Object c = new Object();//obj 3 a = null;//obj 1能夠被回收了 }//obj 3能夠回收了 }//obj 2能夠被回收了
分析dump文件,咱們能夠用jdk裏面提供的jhat工具,執行
jhat xxx.dump
jhat加載解析xxx.dump文件,並開啓一個簡易的web服務,默認端口爲7000,能夠經過瀏覽器查看內存中的一些統計信息
通常使用方法
一、瀏覽器打開http:/127.0.0.1:7000
會列出一些功能,包括package下面各個類的概覽,及各個功能導航
二、點擊頁面的堆內存統計
有一個表格,對象類型,實例個數,實例所佔用內存大小,哪一種類型的對象佔用了內存最多一目瞭然
三、點擊其中認爲內存消耗太多的類名查看類詳情
主要展示該類下面各個實例的大小,以及一些連接導航
四、點擊references summary by type
若是某種類型的對象太多,那麼有多是引用它的那個類的對象太多
基本上一些簡單頁面的查詢,結合原代碼,就能夠初步定位內存泄漏的地方
綜上,dump文件結構仍是比較簡單的,這對於分析線程的執行狀況很是有用,也是每個Java程序員必須掌握的高級技能之一,你學會了嗎?