您好,登錄后才能下訂單哦!
這篇文章主要介紹了java中如何獲取JVM dump文件,具有一定借鑒價值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。
java內存dump是jvm運行時內存的一份快照,利用它可以分析是否存在內存浪費,可以檢查內存管理是否合理,當發(fā)生OOM的時候,可以找出問題的原因。那么dump文件的內容是什么樣的呢?我們一步一步來
獲取dump文件的方式分為主動和被動
主動方式:
1.利用jmap,也是最常用的方式:jmap -dump:[live],format=b,file=
2.利用jcmd,jcmd GC.heap_dump
3.使用VisualVM,可以界面操作進行dump內存
4.通過JMX的方式
MBeanServer server = ManagementFactory.getPlatformMBeanServer(); HotSpotDiagnosticMXBean mxBean = ManagementFactory.newPlatformMXBeanProxy(server, "com.sun.management:type=HotSpotDiagnostic", HotSpotDiagnosticMXBean.class); mxBean.dumpHeap(filePath, live);
被動方式:
被動方式就是我們通常的OOM事件了,通過設置參數(shù)-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=
結構示意圖
dump文件是堆內存的映射,由文件頭和一系列內容塊組成
由musk, 版本,identifierSize, 時間4部分組成
1、musk:4個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個byte數(shù)字,值為4或者8,表示一個引用所占用的byte數(shù)
4、time:8個byte,dump文件生成時間
1.基本類型(8種基本類型),它們占用byte數(shù)固定不變,每生成一個對象它們就需要給它們賦初始值,分配空間
2.是引用類型,表示一個對象,在類中只有一個引用,引用只是一個數(shù)值,所占用的空間大小為identifierSize,被引用對象即將在堆中的另一個地方
例如定義一個類
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
定義一個執(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
結果:
person size:[32]B
class size:[504]B
每個塊都是塊頭和塊體組成
塊頭由1個byte的塊類型,4個byte的時間time,4個byte的長度表示此內容塊占用byte數(shù)
type類型一般有5種,字符串,類,棧楨,棧,及dump塊
1.字符串,由identifierSize個byte的字符串id,后面是(length-identifierSize)個byte的字符串內容(后續(xù)對字符串是直接引用的這里面的id)
2.類,由4個byte的類序列(在棧楨中使用),identifierSize個byte的類id(解析類的時候用到),4個byte的序列id(暫未使用),identifierSize個byte的類名id
3.棧楨,由identifierSize個byte的楨id,identifierSize個byte的方法名id,identifierSize個byte的方法標識id,identifierSize個byte的類文件名id,4個byte的類序列,4個byte的行號
4.棧,由4個byte的棧序號,4個byte的線程序號,4個byte的楨數(shù)量,后面就是若干個identifierSize個byte的楨id
5.dump塊就是所有對象的內容了,每個對象由1個byte的子類型,和對象內容結成,子類型有6種,gc root, 線程對象,類,對象,基本類型數(shù)組,對象數(shù)組
gc root有4種結構,8種類型
1,identifierSize個byte的對象id,類型有SYSTEM_CLASS,BUSY_MONITOR, 及未UNKNOWN
2.identifierSize個byte的對象id,4個byte的線程序列號,類型有NATIVE_STACK,THREAD_BLOCK
3.identifierSize個byte的對象id,4個byte的線程序列號,4個byte的棧楨深度,類型有JAVA_LOCAL,NATIVE_LOCAL
4.identifierSize個byte的對象id,identifierSize個byte的global refId(暫未使用),類型有NATIVE_STATIC
gc root示意圖
gc root為垃圾收集追溯的源頭,每個gc root都指向一個初始對象,無法追溯的對象是要被回收掉的
系統(tǒng)類,只有classLoader為null的類才是gc root,每個類都是一個gc root
線程棧,線程中方法參數(shù),局部變量都是gc root,每個對象都是一個gc root
系統(tǒng)保留對象,每個對象都是一個gc root
1.identifierSize個byte的類對象id
2.4個byte的棧序列號
3.identifierSize個byte的父類對象id,
4.identifierSize個byte的classLoader對象id,
5.identifierSize個byte的Signer對象id,
6.identifierSize個byte的protection domain對象id,
7.identifierSize個byte的保留id1和id2,
8.4個byte的類實例對象大小,
9.2個byte的常量個數(shù),后面是每個常量的,2個byte的下標,1個byte的常量類型,和若干個byte的內容,內容根據(jù)類型來決定(boolean/byte為1個byte, char/short為2個byte,float/int為4個byte, double/long為8個byte,引用類型為identifierSize個byte)
10.2個byte的靜態(tài)變量個數(shù),后面是每個靜態(tài)變量的,identifierSize個byte的變量名id, 1個byte的變量類型,和若干個byte的內容,內容根據(jù)類型來決定(見類對象基本信息的第9條)
11.2個byte的成員變量個數(shù),后面是每個成員變量的,identifierSize個byte的變量名id,1個byte的變量類型
(1)類里面的常量很多地方都沒有用上,所以常量個數(shù)一般為0
(2)類的靜態(tài)變量的名稱類型及值是放在類對象里面的,成員變量的名稱和類型也是放在類對象里面的,但是實例的值是放在實例對象里面的
1、基本信息:
identifierSize個byte的實例對象id
4個byte的棧序列號
identifierSize個byte的類id
4個byte的占用字節(jié)數(shù)
實例的變量的值
2、說明:
實例的值為實例對象的成員變量值,順序為當前類的變量值,順序為類對象基本信息中第11條中的順序,
然后是父類的變量值變量的值基本類型都有默認值,引用類型默認值為0,占用字節(jié)數(shù)(見類對象基本信息的第9條)
identifierSize個byte的數(shù)組對象id
4個byte的棧序列號
4個byte的數(shù)組長度
1個byte的元素類型
元素的值列表
元素的值(見類對象基本信息的第9條)
基本信息:
identifierSize個byte的數(shù)組對象id
4個byte的棧序列號
4個byte的數(shù)組長度
identifierSize個byte的元素類id
元素的值列表
當一個線程啟動的時候,進程會去系統(tǒng)內存生成一個線程棧
每當發(fā)生一次方法調用,就會向棧中壓入一個棧楨,當方法調用完之后,棧楨會退出
在運行過程中,如果有對象的new操作的時候,進程會去堆區(qū)申請一塊內存
關于運行時內存的詳細情況,可以查找相關的資料
如果一個對象不能騎過gc root引用可達,那么這個對象就可能要被回收
對象回收規(guī)則包括
實例屬性被實例引用,只有當實例被回收了實例屬性才能被回收(只針對強引用)
類對象被實例引用,只有當一個類的所有實例都被回收了,類才能被回收類
對象的父類,classLoader對象,signer對象, protection domain對象被類引用,只有當類被回收了,這些才能被回收
局部變量(線程棧中)的作用域為一個大括號
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文件,并開啟一個簡易的web服務,默認端口為7000,可以通過瀏覽器查看內存中的一些統(tǒng)計信息
一般使用方法
會列出一些功能,包括package下面各個類的概覽,及各個功能導航
有一個表格,對象類型,實例個數(shù),實例所占用內存大小,哪種類型的對象占用了內存最多一目了然
主要展現(xiàn)該類下面各個實例的大小,以及一些鏈接導航
如果某種類型的對象太多,那么有可能是引用它的那個類的對象太多
基本上一些簡單頁面的查詢,結合原代碼,就可以初步定位內存泄漏的地方
1.SpringMVC,Spring Web MVC是一種基于Java的實現(xiàn)了Web MVC設計模式的請求驅動類型的輕量級Web框架。2.Shiro,Apache Shiro是Java的一個安全框架。3.Mybatis,MyBatis 是支持普通 SQL查詢,存儲過程和高級映射的優(yōu)秀持久層框架。4.Dubbo,Dubbo是一個分布式服務框架。5.Maven,Maven是個項目管理和構建自動化工具。6.RabbitMQ,RabbitMQ是用Erlang實現(xiàn)的一個高并發(fā)高可靠AMQP消息隊列服務器。7.Ehcache,EhCache 是一個純Java的進程內緩存框架。
感謝你能夠認真閱讀完這篇文章,希望小編分享的“java中如何獲取JVM dump文件”這篇文章對大家有幫助,同時也希望大家多多支持億速云,關注億速云行業(yè)資訊頻道,更多相關知識等著你來學習!
免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經查實,將立刻刪除涉嫌侵權內容。