日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷解決方案
干貨分享丨jvm系列:dump文件深度分析

JVM dump

在朝陽(yáng)縣等地區(qū),都構(gòu)建了全面的區(qū)域性戰(zhàn)略布局,加強(qiáng)發(fā)展的系統(tǒng)性、市場(chǎng)前瞻性、產(chǎn)品創(chuàng)新能力,以專注、極致的服務(wù)理念,為客戶提供成都網(wǎng)站設(shè)計(jì)、做網(wǎng)站 網(wǎng)站設(shè)計(jì)制作按需網(wǎng)站設(shè)計(jì),公司網(wǎng)站建設(shè),企業(yè)網(wǎng)站建設(shè),品牌網(wǎng)站設(shè)計(jì),全網(wǎng)營(yíng)銷推廣,成都外貿(mào)網(wǎng)站制作,朝陽(yáng)縣網(wǎng)站建設(shè)費(fèi)用合理。

java內(nèi)存dump是jvm運(yùn)行時(shí)內(nèi)存的一份快照,利用它可以分析是否存在內(nèi)存浪費(fèi),可以檢查內(nèi)存管理是否合理,當(dāng)發(fā)生OOM的時(shí)候,可以找出問題的原因。那么dump文件的內(nèi)容是什么樣的呢?我們一步一步來(lái)

獲取JVM dump文件

獲取dump文件的方式分為主動(dòng)和被動(dòng)

i.主動(dòng)方式:

1.利用jmap,也是最常用的方式:jmap -dump:[live],format=b,file=

2.利用jcmd,jcmd GC.heap_dump

3.使用VisualVM,可以界面操作進(jìn)行dump內(nèi)存

4.通過JMX的方式 

 
 
 
 
  1. MBeanServer server = ManagementFactory.getPlatformMBeanServer();  
  2. HotSpotDiagnosticMXBean mxBean = ManagementFactory.newPlatformMXBeanProxy(server, "com.sun.management:type=HotSpotDiagnostic", HotSpotDiagnosticMXBean.class); 
  3. mxBean.dumpHeap(filePath, live); 

參考(https://www.baeldung.com/java...

ii.被動(dòng)方式:

被動(dòng)方式就是我們通常的OOM事件了,通過設(shè)置參數(shù)-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=

dump文件分析

結(jié)構(gòu)示意圖

結(jié)構(gòu)詳解

dump文件是堆內(nèi)存的映射,由文件頭和一系列內(nèi)容塊組成

文件頭

由musk, 版本,identifierSize, 時(shí)間4部分組成

1、musk:4個(gè)byte,內(nèi)容為'J', 'A', 'V', 'A'即JAVA

2、version:若干byte,值有以下三種 

 
 
 
 
  1. " PROFILE 1.0\0",  
  2. " PROFILE 1.0.1\0",  
  3. " PROFILE 1.0.2\0"  

3、identifierSize:4個(gè)byte數(shù)字,值為4或者8,表示一個(gè)引用所占用的byte數(shù)

4、time:8個(gè)byte,dump文件生成時(shí)間

說(shuō)明:java一個(gè)類的成員變量有兩種類型

  1. 基本類型(8種基本類型),它們占用byte數(shù)固定不變,每生成一個(gè)對(duì)象它們就需要給它們賦初始值,分配空間
  2. 是引用類型,表示一個(gè)對(duì)象,在類中只有一個(gè)引用,引用只是一個(gè)數(shù)值,所占用的空間大小為identifierSize,被引用對(duì)象即將在堆中的另一個(gè)地方

        例如定義一個(gè)類 

 
 
 
 
  1. public class Person {  
  2.  private int age;//4個(gè)byte  
  3.  private String name;//identifierSize個(gè)byte  
  4.  private double weight;//8個(gè)byte  
  5. }  

當(dāng)我們?cè)趎ew Person()的時(shí)候

它就需要申請(qǐng)一個(gè)空間,空間大小為 對(duì)象頭大小+4+identifierSize+8個(gè)byte

對(duì)象大小的測(cè)量:

jdk提供一個(gè)測(cè)試對(duì)象占用內(nèi)存大小的工具Instrumentation,但是Instrumentation沒法直接引用到,需要通過agent來(lái)引用到

定義一個(gè)Premain類, javac Premain.java 

 
 
 
 
  1. //Premain.java  
  2. public class Premain {  
  3.     public static java.lang.instrument.Instrumentation inst;  
  4.     public static void premain(String args, java.lang.instrument.Instrumentation inst) {  
  5.         Premain.inst = inst;  
  6.     }  
  7. }  

編寫一個(gè)Manifest文件 

 
 
 
 
  1. manifest.mf  
  2. Manifest-Version: 1.0  
  3. Premain-Class: Premain  
  4. Can-Redefine-Classes: true  
  5. Can-Retransform-Classes: true  

打包 

 
 
 
 
  1. jar -cmf manifest.mf premain.jar Premain.class 

定義一個(gè)執(zhí)行類, javac PersonTest.java 

 
 
 
 
  1. //PersonTest.java  
  2. public class PersonTest {  
  3.     public static void main(String[] args) throws Exception {  
  4.         Class clazz = Class.forName("Premain");  
  5.         if (clazz != null) {  
  6.             Person p = new Person();  
  7.             java.lang.instrument.Instrumentation inst = (java.lang.instrument.Instrumentation)clazz.getDeclaredField("inst").get(null);  
  8.             System.out.println("person size:[" + inst.getObjectSize(p) + "]B");  
  9.             System.out.println("class size:[" + inst.getObjectSize(p.getClass()) + "]B"); 
  10.         }  
  11.     }  
  12. }  

帶agent執(zhí)行 

 
 
 
 
  1. java -javaagent:premain.jar PersonTest 

結(jié)果: 

 
 
 
 
  1. person size:[32]B  
  2. class size:[504]B  

內(nèi)容塊

每個(gè)塊都是塊頭和塊體組成

塊頭

塊頭由1個(gè)byte的塊類型,4個(gè)byte的時(shí)間time,4個(gè)byte的長(zhǎng)度表示此內(nèi)容塊占用byte數(shù)

type類型一般有5種,字符串,類,棧楨,棧,及dump塊

  1. 字符串,由identifierSize個(gè)byte的字符串id,后面是(length-identifierSize)個(gè)byte的字符串內(nèi)容(后續(xù)對(duì)字符串是直接引用的這里面的id)
  2. 類,由4個(gè)byte的類序列(在棧楨中使用),identifierSize個(gè)byte的類id(解析類的時(shí)候用到),4個(gè)byte的序列id(暫未使用),identifierSize個(gè)byte的類名id
  3. 棧楨,由identifierSize個(gè)byte的楨id,identifierSize個(gè)byte的方法名id,identifierSize個(gè)byte的方法標(biāo)識(shí)id,identifierSize個(gè)byte的類文件名id,4個(gè)byte的類序列,4個(gè)byte的行號(hào)
  4. 棧,由4個(gè)byte的棧序號(hào),4個(gè)byte的線程序號(hào),4個(gè)byte的楨數(shù)量,后面就是若干個(gè)identifierSize個(gè)byte的楨id
  5. dump塊就是所有對(duì)象的內(nèi)容了,每個(gè)對(duì)象由1個(gè)byte的子類型,和對(duì)象內(nèi)容結(jié)成,子類型有6種,gc root, 線程對(duì)象,類,對(duì)象,基本類型數(shù)組,對(duì)象數(shù)組

gc root

gc root有4種結(jié)構(gòu),8種類型

  1. identifierSize個(gè)byte的對(duì)象id,類型有SYSTEM_CLASS,BUSY_MONITOR, 及未UNKNOWN
  2. identifierSize個(gè)byte的對(duì)象id,4個(gè)byte的線程序列號(hào),類型有NATIVE_STACK,THREAD_BLOCK
  3. identifierSize個(gè)byte的對(duì)象id,4個(gè)byte的線程序列號(hào),4個(gè)byte的棧楨深度,類型有JAVA_LOCAL,NATIVE_LOCAL
  4. identifierSize個(gè)byte的對(duì)象id,identifierSize個(gè)byte的global refId(暫未使用),類型有NATIVE_STATIC

gc root示意圖

gc root為垃圾收集追溯的源頭,每個(gè)gc root都指向一個(gè)初始對(duì)象,無(wú)法追溯的對(duì)象是要被回收掉的

系統(tǒng)類,只有classLoader為null的類才是gc root,每個(gè)類都是一個(gè)gc root

線程棧,線程中方法參數(shù),局部變量都是gc root,每個(gè)對(duì)象都是一個(gè)gc root

系統(tǒng)保留對(duì)象,每個(gè)對(duì)象都是一個(gè)gc root

類對(duì)象

1、基本信息:

  1. identifierSize個(gè)byte的類對(duì)象id
  2. 4個(gè)byte的棧序列號(hào),
  3. identifierSize個(gè)byte的父類對(duì)象id,
  4. identifierSize個(gè)byte的classLoader對(duì)象id,
  5. identifierSize個(gè)byte的Signer對(duì)象id,
  6. identifierSize個(gè)byte的protection domain對(duì)象id,
  7. identifierSize個(gè)byte的保留id1和id2,
  8. 4個(gè)byte的類實(shí)例對(duì)象大小,
  9. 2個(gè)byte的常量個(gè)數(shù),后面是每個(gè)常量的,2個(gè)byte的下標(biāo),1個(gè)byte的常量類型,和若干個(gè)byte的內(nèi)容,內(nèi)容根據(jù)類型來(lái)決定(boolean/byte為1個(gè)byte, char/short為2個(gè)byte,float/int為4個(gè)byte, double/long為8個(gè)byte,引用類型為identifierSize個(gè)byte)

     10. 2個(gè)byte的靜態(tài)變量個(gè)數(shù),后面是每個(gè)靜態(tài)變量的,identifierSize個(gè)byte的變量名id, 1個(gè)byte的變量類型,和若干個(gè)byte的內(nèi)容,內(nèi)容根據(jù)類型來(lái)決定(見類對(duì)象基本信息的第9條)

      11.  2個(gè)byte的成員變量個(gè)數(shù),后面是每個(gè)成員變量的,identifierSize個(gè)byte的變量名id,1個(gè)byte的變量類型

2、說(shuō)明:

(1)類里面的常量很多地方都沒有用上,所以常量個(gè)數(shù)一般為0

(2)類的靜態(tài)變量的名稱類型及值是放在類對(duì)象里面的,成員變量的名稱和類型也是放在類對(duì)象里面的,但是實(shí)例的值是放在實(shí)例對(duì)象里面的

實(shí)例對(duì)象

1、基本信息:

  1. identifierSize個(gè)byte的實(shí)例對(duì)象id
  2. 4個(gè)byte的棧序列號(hào)
  3. identifierSize個(gè)byte的類id
  4. 4個(gè)byte的占用字節(jié)數(shù)
  5. 實(shí)例的變量的值

2、說(shuō)明:

  1. 實(shí)例的值為實(shí)例對(duì)象的成員變量值,順序?yàn)楫?dāng)前類的變量值,順序?yàn)轭悓?duì)象基本信息中第11條中的順序,然后是父類的變量值
  2. 變量的值基本類型都有默認(rèn)值,引用類型默認(rèn)值為0,占用字節(jié)數(shù)(見類對(duì)象基本信息的第9條)

基本類型數(shù)組

1、基本信息:

  1. identifierSize個(gè)byte的數(shù)組對(duì)象id
  2. 4個(gè)byte的棧序列號(hào)
  3. 4個(gè)byte的數(shù)組長(zhǎng)度
  4. 1個(gè)byte的元素類型
  5. 元素的值列表

2、說(shuō)明:

  1. 元素的值(見類對(duì)象基本信息的第9條)

對(duì)象數(shù)組

1、基本信息:

  1. identifierSize個(gè)byte的數(shù)組對(duì)象id
  2. 4個(gè)byte的棧序列號(hào)
  3. 4個(gè)byte的數(shù)組長(zhǎng)度
  4. identifierSize個(gè)byte的元素類id
  5. 元素的值列表

內(nèi)存分配

當(dāng)一個(gè)線程啟動(dòng)的時(shí)候,進(jìn)程會(huì)去系統(tǒng)內(nèi)存生成一個(gè)線程棧

每當(dāng)發(fā)生一次方法調(diào)用,就會(huì)向棧中壓入一個(gè)棧楨,當(dāng)方法調(diào)用完之后,棧楨會(huì)退出

在運(yùn)行過程中,如果有對(duì)象的new操作的時(shí)候,進(jìn)程會(huì)去堆區(qū)申請(qǐng)一塊內(nèi)存

關(guān)于運(yùn)行時(shí)內(nèi)存的詳細(xì)情況,可以查找相關(guān)的資料

內(nèi)存回收規(guī)則

如果一個(gè)對(duì)象不能騎過gc root引用可達(dá),那么這個(gè)對(duì)象就可能要被回收

對(duì)象回收規(guī)則包括

  1. 實(shí)例屬性被實(shí)例引用,只有當(dāng)實(shí)例被回收了實(shí)例屬性才能被回收(只針對(duì)強(qiáng)引用)
  2. 類對(duì)象被實(shí)例引用,只有當(dāng)一個(gè)類的所有實(shí)例都被回收了,類才能被回收
  3. 類對(duì)象的父類,classLoader對(duì)象,signer對(duì)象, protection domain對(duì)象被類引用,只有當(dāng)類被回收了,這些才能被回收
  4. 局部變量(線程棧中)的作用域?yàn)橐粋€(gè)大括號(hào) 
 
 
 
 
  1. public void test(){  
  2. Object a = new Object();//obj 1  
  3. Object b = new Object();//obj 2  
  4. {  
  5. Object c = new Object();//obj 3  
  6. a = null;//obj 1可以被回收了  
  7. }//obj 3可以回收了  
  8. }//obj 2可以被回收了 

 

分析工具簡(jiǎn)介

分析dump文件,我們可以用jdk里面提供的jhat工具,執(zhí)行 

 
 
 
 
  1. jhat xxx.dump 

jhat加載解析xxx.dump文件,并開啟一個(gè)簡(jiǎn)易的web服務(wù),默認(rèn)端口為7000,可以通過瀏覽器查看內(nèi)存中的一些統(tǒng)計(jì)信息

一般使用方法

1、瀏覽器打開http:/127.0.0.1:7000

會(huì)列出一些功能,包括package下面各個(gè)類的概覽,及各個(gè)功能導(dǎo)航

2、點(diǎn)擊頁(yè)面的堆內(nèi)存統(tǒng)計(jì)

有一個(gè)表格,對(duì)象類型,實(shí)例個(gè)數(shù),實(shí)例所占用內(nèi)存大小,哪種類型的對(duì)象占用了內(nèi)存最多一目了然

3、點(diǎn)擊其中認(rèn)為內(nèi)存消耗太多的類名查看類詳情

主要展現(xiàn)該類下面各個(gè)實(shí)例的大小,以及一些鏈接導(dǎo)航

4、點(diǎn)擊references summary by type

如果某種類型的對(duì)象太多,那么有可能是引用它的那個(gè)類的對(duì)象太多

基本上一些簡(jiǎn)單頁(yè)面的查詢,結(jié)合原代碼,就可以初步定位內(nèi)存泄漏的地方

綜上,dump文件結(jié)構(gòu)還是比較簡(jiǎn)單的,這對(duì)于分析線程的執(zhí)行情況非常有用,也是每一個(gè)Java程序員必須掌握的高級(jí)技能之一,你學(xué)會(huì)了嗎?


網(wǎng)站標(biāo)題:干貨分享丨jvm系列:dump文件深度分析
網(wǎng)頁(yè)路徑:http://www.5511xx.com/article/dpepsds.html