- 資訊首頁(yè) > 開(kāi)發(fā)技術(shù) >
- 深度分析java dump文件
java內存dump是jvm運行時(shí)內存的一份快照,利用它可以分析是否存在內存浪費,可以檢查內存管理是否合理,當發(fā)生OOM的時(shí)候,可以找出問(wèn)題的原因。那么dump文件的內容是什么樣的呢?我們一步一步來(lái)
獲取dump文件的方式分為主動(dòng)和被動(dòng)
主動(dòng)方式:
1.利用jmap,也是最常用的方式:jmap -dump:[live],format=b,file=
2.利用jcmd,jcmd GC.heap_dump
3.使用VisualVM,可以界面操作進(jìn)行dump內存
4.通過(guò)JMX的方式
MBeanServer server = ManagementFactory.getPlatformMBeanServer(); HotSpotDiagnosticMXBean mxBean = ManagementFactory.newPlatformMXBeanProxy(server, "com.sun.management:type=HotSpotDiagnostic", HotSpotDiagnosticMXBean.class); mxBean.dumpHeap(filePath, live);
參考()
被動(dòng)方式:
被動(dòng)方式就是我們通常的OOM事件了,通過(guò)設置參數-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=
結構示意圖
dump文件是堆內存的映射,由文件頭和一系列內容塊組成
由musk, 版本,identifierSize, 時(shí)間4部分組成
1、musk:4個(gè)byte,內容為'J', 'A', 'V', 'A'即JAVA
2、version:若干byte,值有以下三種
" PROFILE 1.0\0",
" PROFILE 1.0.1\0",
" PROFILE 1.0.2\0"
3、identifierSize:4個(gè)byte數字,值為4或者8,表示一個(gè)引用所占用的byte數
4、time:8個(gè)byte,dump文件生成時(shí)間
1.基本類(lèi)型(8種基本類(lèi)型),它們占用byte數固定不變,每生成一個(gè)對象它們就需要給它們賦初始值,分配空間
2.是引用類(lèi)型,表示一個(gè)對象,在類(lèi)中只有一個(gè)引用,引用只是一個(gè)數值,所占用的空間大小為identifierSize,被引用對象即將在堆中的另一個(gè)地方
例如定義一個(gè)類(lèi)
public class Person { private int age;//4個(gè)byte private String name;//identifierSize個(gè)byte private double weight;//8個(gè)byte }
當我們在new Person()的時(shí)候
它就需要申請一個(gè)空間,空間大小為 對象頭大小+4+identifierSize+8個(gè)byte
對象大小的測量:
jdk提供一個(gè)測試對象占用內存大小的工具Instrumentation,但是Instrumentation沒(méi)法直接引用到,需要通過(guò)agent來(lái)引用到
定義一個(gè)Premain類(lèi), 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; } }
編寫(xiě)一個(gè)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
定義一個(gè)執行類(lèi), 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
每個(gè)塊都是塊頭和塊體組成
塊頭由1個(gè)byte的塊類(lèi)型,4個(gè)byte的時(shí)間time,4個(gè)byte的長(cháng)度表示此內容塊占用byte數
type類(lèi)型一般有5種,字符串,類(lèi),棧楨,棧,及dump塊
1.字符串,由identifierSize個(gè)byte的字符串id,后面是(length-identifierSize)個(gè)byte的字符串內容(后續對字符串是直接引用的這里面的id)
2.類(lèi),由4個(gè)byte的類(lèi)序列(在棧楨中使用),identifierSize個(gè)byte的類(lèi)id(解析類(lèi)的時(shí)候用到),4個(gè)byte的序列id(暫未使用),identifierSize個(gè)byte的類(lèi)名id
3.棧楨,由identifierSize個(gè)byte的楨id,identifierSize個(gè)byte的方法名id,identifierSize個(gè)byte的方法標識id,identifierSize個(gè)byte的類(lèi)文件名id,4個(gè)byte的類(lèi)序列,4個(gè)byte的行號
4.棧,由4個(gè)byte的棧序號,4個(gè)byte的線(xiàn)程序號,4個(gè)byte的楨數量,后面就是若干個(gè)identifierSize個(gè)byte的楨id
5.dump塊就是所有對象的內容了,每個(gè)對象由1個(gè)byte的子類(lèi)型,和對象內容結成,子類(lèi)型有6種,gc root, 線(xiàn)程對象,類(lèi),對象,基本類(lèi)型數組,對象數組
gc root有4種結構,8種類(lèi)型
1,identifierSize個(gè)byte的對象id,類(lèi)型有SYSTEM_CLASS,BUSY_MONITOR, 及未UNKNOWN
2.identifierSize個(gè)byte的對象id,4個(gè)byte的線(xiàn)程序列號,類(lèi)型有NATIVE_STACK,THREAD_BLOCK
3.identifierSize個(gè)byte的對象id,4個(gè)byte的線(xiàn)程序列號,4個(gè)byte的棧楨深度,類(lèi)型有JAVA_LOCAL,NATIVE_LOCAL
4.identifierSize個(gè)byte的對象id,identifierSize個(gè)byte的global refId(暫未使用),類(lèi)型有NATIVE_STATIC
gc root示意圖
gc root為垃圾收集追溯的源頭,每個(gè)gc root都指向一個(gè)初始對象,無(wú)法追溯的對象是要被回收掉的
系統類(lèi),只有classLoader為null的類(lèi)才是gc root,每個(gè)類(lèi)都是一個(gè)gc root
線(xiàn)程棧,線(xiàn)程中方法參數,局部變量都是gc root,每個(gè)對象都是一個(gè)gc root
系統保留對象,每個(gè)對象都是一個(gè)gc root
1.identifierSize個(gè)byte的類(lèi)對象id
2.4個(gè)byte的棧序列號
3.identifierSize個(gè)byte的父類(lèi)對象id,
4.identifierSize個(gè)byte的classLoader對象id,
5.identifierSize個(gè)byte的Signer對象id,
6.identifierSize個(gè)byte的protection domain對象id,
7.identifierSize個(gè)byte的保留id1和id2,
8.4個(gè)byte的類(lèi)實(shí)例對象大小,
9.2個(gè)byte的常量個(gè)數,后面是每個(gè)常量的,2個(gè)byte的下標,1個(gè)byte的常量類(lèi)型,和若干個(gè)byte的內容,內容根據類(lèi)型來(lái)決定(boolean/byte為1個(gè)byte, char/short為2個(gè)byte,float/int為4個(gè)byte, double/long為8個(gè)byte,引用類(lèi)型為identifierSize個(gè)byte)
10.2個(gè)byte的靜態(tài)變量個(gè)數,后面是每個(gè)靜態(tài)變量的,identifierSize個(gè)byte的變量名id, 1個(gè)byte的變量類(lèi)型,和若干個(gè)byte的內容,內容根據類(lèi)型來(lái)決定(見(jiàn)類(lèi)對象基本信息的第9條)
11.2個(gè)byte的成員變量個(gè)數,后面是每個(gè)成員變量的,identifierSize個(gè)byte的變量名id,1個(gè)byte的變量類(lèi)型
(1)類(lèi)里面的常量很多地方都沒(méi)有用上,所以常量個(gè)數一般為0
(2)類(lèi)的靜態(tài)變量的名稱(chēng)類(lèi)型及值是放在類(lèi)對象里面的,成員變量的名稱(chēng)和類(lèi)型也是放在類(lèi)對象里面的,但是實(shí)例的值是放在實(shí)例對象里面的
1、基本信息:
2、說(shuō)明:
元素的值(見(jiàn)類(lèi)對象基本信息的第9條)
基本信息:
當一個(gè)線(xiàn)程啟動(dòng)的時(shí)候,進(jìn)程會(huì )去系統內存生成一個(gè)線(xiàn)程棧
每當發(fā)生一次方法調用,就會(huì )向棧中壓入一個(gè)棧楨,當方法調用完之后,棧楨會(huì )退出
在運行過(guò)程中,如果有對象的new操作的時(shí)候,進(jìn)程會(huì )去堆區申請一塊內存
關(guān)于運行時(shí)內存的詳細情況,可以查找相關(guān)的資料
如果一個(gè)對象不能騎過(guò)gc root引用可達,那么這個(gè)對象就可能要被回收
對象回收規則包括
實(shí)例屬性被實(shí)例引用,只有當實(shí)例被回收了實(shí)例屬性才能被回收(只針對強引用)
類(lèi)對象被實(shí)例引用,只有當一個(gè)類(lèi)的所有實(shí)例都被回收了,類(lèi)才能被回收類(lèi)
對象的父類(lèi),classLoader對象,signer對象, protection domain對象被類(lèi)引用,只有當類(lèi)被回收了,這些才能被回收
局部變量(線(xiàn)程棧中)的作用域為一個(gè)大括號
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文件,并開(kāi)啟一個(gè)簡(jiǎn)易的web服務(wù),默認端口為7000,可以通過(guò)瀏覽器查看內存中的一些統計信息
一般使用方法
會(huì )列出一些功能,包括package下面各個(gè)類(lèi)的概覽,及各個(gè)功能導航
有一個(gè)表格,對象類(lèi)型,實(shí)例個(gè)數,實(shí)例所占用內存大小,哪種類(lèi)型的對象占用了內存最多一目了然
主要展現該類(lèi)下面各個(gè)實(shí)例的大小,以及一些鏈接導航
如果某種類(lèi)型的對象太多,那么有可能是引用它的那個(gè)類(lèi)的對象太多
基本上一些簡(jiǎn)單頁(yè)面的查詢(xún),結合原代碼,就可以初步定位內存泄漏的地方
綜上,dump文件結構還是比較簡(jiǎn)單的,這對于分析線(xiàn)程的執行情況非常有用,也是每一個(gè)Java程序員必須掌握的高級技能之一,你學(xué)會(huì )了嗎?
以上就是深度分析java dump文件的詳細內容,更多關(guān)于java dump文件的資料請關(guān)注腳本之家其它相關(guān)文章!
免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng )、來(lái)自互聯(lián)網(wǎng)轉載和分享為主,文章觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權請聯(lián)系QQ:712375056 進(jìn)行舉報,并提供相關(guān)證據,一經(jīng)查實(shí),將立刻刪除涉嫌侵權內容。
Copyright ? 2009-2021 56dr.com. All Rights Reserved. 特網(wǎng)科技 特網(wǎng)云 版權所有 珠海市特網(wǎng)科技有限公司 粵ICP備16109289號
域名注冊服務(wù)機構:阿里云計算有限公司(萬(wàn)網(wǎng)) 域名服務(wù)機構:煙臺帝思普網(wǎng)絡(luò )科技有限公司(DNSPod) CDN服務(wù):阿里云計算有限公司 中國互聯(lián)網(wǎng)舉報中心 增值電信業(yè)務(wù)經(jīng)營(yíng)許可證B2
建議您使用Chrome、Firefox、Edge、IE10及以上版本和360等主流瀏覽器瀏覽本網(wǎng)站