掃二維碼與項(xiàng)目經(jīng)理溝通
我們?cè)谖⑿派?4小時(shí)期待你的聲音
解答本文疑問/技術(shù)咨詢/運(yùn)營咨詢/技術(shù)建議/互聯(lián)網(wǎng)交流
JVM dump

在朝陽縣等地區(qū),都構(gòu)建了全面的區(qū)域性戰(zhàn)略布局,加強(qiáng)發(fā)展的系統(tǒ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)營銷推廣,成都外貿(mào)網(wǎ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)容是什么樣的呢?我們一步一步來
獲取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的方式
- 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...
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,值有以下三種
- " PROFILE 1.0\0",
- " PROFILE 1.0.1\0",
- " PROFILE 1.0.2\0"
3、identifierSize:4個(gè)byte數(shù)字,值為4或者8,表示一個(gè)引用所占用的byte數(shù)
4、time:8個(gè)byte,dump文件生成時(shí)間
說明:java一個(gè)類的成員變量有兩種類型
例如定義一個(gè)類
- public class Person {
- private int age;//4個(gè)byte
- private String name;//identifierSize個(gè)byte
- private double weight;//8個(gè)byte
- }
當(dāng)我們?cè)趎ew Person()的時(shí)候
它就需要申請(qǐng)一個(gè)空間,空間大小為 對(duì)象頭大小+4+identifierSize+8個(gè)byte
對(duì)象大小的測量:
jdk提供一個(gè)測試對(duì)象占用內(nèi)存大小的工具Instrumentation,但是Instrumentation沒法直接引用到,需要通過agent來引用到
定義一個(gè)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;
- }
- }
編寫一個(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è)執(zhí)行類, 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執(zhí)行
- java -javaagent:premain.jar PersonTest
結(jié)果:
- person size:[32]B
- class size:[504]B
內(nèi)容塊
每個(gè)塊都是塊頭和塊體組成
塊頭
塊頭由1個(gè)byte的塊類型,4個(gè)byte的時(shí)間time,4個(gè)byte的長度表示此內(nèi)容塊占用byte數(shù)
type類型一般有5種,字符串,類,棧楨,棧,及dump塊
gc root
gc root有4種結(jié)構(gòu),8種類型
gc root示意圖
gc root為垃圾收集追溯的源頭,每個(gè)gc root都指向一個(gè)初始對(duì)象,無法追溯的對(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、基本信息:
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ù)類型來決定(見類對(duì)象基本信息的第9條)
11. 2個(gè)byte的成員變量個(gè)數(shù),后面是每個(gè)成員變量的,identifierSize個(gè)byte的變量名id,1個(gè)byte的變量類型
2、說明:
(1)類里面的常量很多地方都沒有用上,所以常量個(gè)數(shù)一般為0
(2)類的靜態(tài)變量的名稱類型及值是放在類對(duì)象里面的,成員變量的名稱和類型也是放在類對(duì)象里面的,但是實(shí)例的值是放在實(shí)例對(duì)象里面的
實(shí)例對(duì)象
1、基本信息:
2、說明:
基本類型數(shù)組
1、基本信息:
2、說明:
對(duì)象數(shù)組
1、基本信息:
內(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ī)則包括
- 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工具,執(zhí)行
- jhat xxx.dump
jhat加載解析xxx.dump文件,并開啟一個(gè)簡易的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)擊頁面的堆內(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èi)存泄漏的地方
綜上,dump文件結(jié)構(gòu)還是比較簡單的,這對(duì)于分析線程的執(zhí)行情況非常有用,也是每一個(gè)Java程序員必須掌握的高級(jí)技能之一,你學(xué)會(huì)了嗎?

我們?cè)谖⑿派?4小時(shí)期待你的聲音
解答本文疑問/技術(shù)咨詢/運(yùn)營咨詢/技術(shù)建議/互聯(lián)網(wǎng)交流