jmap 文件解析_干货分享丨jvm系列:dump文件深度分析

摘要:java内存dump是jvm运行时内存的一份快照,利用它可以分析是否存在内存浪费,可以检查内存管理是否合理,当发生OOM的时候,可以找出问题的原因。那么dump文件的内容是什么样的呢?

JVM dump

java内存dump是jvm运行时内存的一份快照,利用它可以分析是否存在内存浪费,可以检查内存管理是否合理,当发生OOM的时候,可以找出问题的原因。那么dump文件的内容是什么样的呢?我们一步一步来

获取JVM dump文件

获取dump文件的方式分为主动和被动

i.主动方式:

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);

ii.被动方式:

被动方式就是我们通常的OOM事件了,通过设置参数-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=

dump文件分析

结构示意图

1da4a1c68ff286522135b07a7e739b12.png

结构详解

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数字,值为4或者8,表示一个引用所占用的byte数

4、time:8个byte,dump文件生成时间

说明:java一个类的成员变量有两种类型

基本类型(8种基本类型),它们占用byte数固定不变,每生成一个对象它们就需要给它们赋初始值,分配空间

是引用类型,表示一个对象,在类中只有一个引用,引用只是一个数值,所占用的空间大小为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

定义一个执行类, 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块

字符串,由identifierSize个byte的字符串id,后面是(length-identifierSize)个byte的字符串内容(后续对字符串是直接引用的这里面的id)

类,由4个byte的类序列(在栈桢中使用),identifierSize个byte的类id(解析类的时候用到),4个byte的序列id(暂未使用),identifierSize个byte的类名id

栈桢,由identifierSize个byte的桢id,identifierSize个byte的方法名id,identifierSize个byte的方法标识id,identifierSize个byte的类文件名id,4个byte的类序列,4个byte的行号

栈,由4个byte的栈序号,4个byte的线程序号,4个byte的桢数量,后面就是若干个identifierSize个byte的桢id

dump块就是所有对象的内容了,每个对象由1个byte的子类型,和对象内容结成,子类型有6种,gc root, 线程对象,类,对象,基本类型数组,对象数组

gc root

gc root有4种结构,8种类型

identifierSize个byte的对象id,类型有SYSTEM_CLASS,BUSY_MONITOR, 及未UNKNOWN

identifierSize个byte的对象id,4个byte的线程序列号,类型有NATIVE_STACK,THREAD_BLOCK

identifierSize个byte的对象id,4个byte的线程序列号,4个byte的栈桢深度,类型有JAVA_LOCAL,NATIVE_LOCAL

identifierSize个byte的对象id,identifierSize个byte的global refId(暂未使用),类型有NATIVE_STATIC

gc root示意图

gc root为垃圾收集追溯的源头,每个gc root都指向一个初始对象,无法追溯的对象是要被回收掉的

f99553c8ae4ac0951890e419945576c1.png

系统类,只有classLoader为null的类才是gc root,每个类都是一个gc root

线程栈,线程中方法参数,局部变量都是gc root,每个对象都是一个gc root

系统保留对象,每个对象都是一个gc root

类对象

1、基本信息:

identifierSize个byte的类对象id

4个byte的栈序列号,

identifierSize个byte的父类对象id,

identifierSize个byte的classLoader对象id,

identifierSize个byte的Signer对象id,

identifierSize个byte的protection domain对象id,

identifierSize个byte的保留id1和id2,

4个byte的类实例对象大小,

2个byte的常量个数,后面是每个常量的,2个byte的下标,1个byte的常量类型,和若干个byte的内容,内容根据类型来决定(boolean/byte为1个byte, char/short为2个byte,float/int为4个byte, double/long为8个byte,引用类型为identifierSize个byte)

2个byte的静态变量个数,后面是每个静态变量的,identifierSize个byte的变量名id, 1个byte的变量类型,和若干个byte的内容,内容根据类型来决定(见类对象基本信息的第9条)

2个byte的成员变量个数,后面是每个成员变量的,identifierSize个byte的变量名id,1个byte的变量类型

2、说明:

(1)类里面的常量很多地方都没有用上,所以常量个数一般为0

(2)类的静态变量的名称类型及值是放在类对象里面的,成员变量的名称和类型也是放在类对象里面的,但是实例的值是放在实例对象里面的

实例对象

1、基本信息:

identifierSize个byte的实例对象id

4个byte的栈序列号

identifierSize个byte的类id

4个byte的占用字节数

实例的变量的值

2、说明:

实例的值为实例对象的成员变量值,顺序为当前类的变量值,顺序为类对象基本信息中第11条中的顺序,然后是父类的变量值

变量的值基本类型都有默认值,引用类型默认值为0,占用字节数(见类对象基本信息的第9条)

基本类型数组

1、基本信息:

identifierSize个byte的数组对象id

4个byte的栈序列号

4个byte的数组长度

1个byte的元素类型

元素的值列表

2、说明:

元素的值(见类对象基本信息的第9条)

对象数组

1、基本信息:

identifierSize个byte的数组对象id

4个byte的栈序列号

4个byte的数组长度

identifierSize个byte的元素类id

元素的值列表

内存分配

b996e6ada33dd6d11e52e94fa892c268.png

当一个线程启动的时候,进程会去系统内存生成一个线程栈

每当发生一次方法调用,就会向栈中压入一个栈桢,当方法调用完之后,栈桢会退出

在运行过程中,如果有对象的new操作的时候,进程会去堆区申请一块内存

关于运行时内存的详细情况,可以查找相关的资料

内存回收规则

如果一个对象不能骑过gc root引用可达,那么这个对象就可能要被回收

对象回收规则包括

实例属性被实例引用,只有当实例被回收了实例属性才能被回收(只针对强引用)

类对象被实例引用,只有当一个类的所有实例都被回收了,类才能被回收

类对象的父类,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工具,执行

jhat xxx.dump

jhat加载解析xxx.dump文件,并开启一个简易的web服务,默认端口为7000,可以通过浏览器查看内存中的一些统计信息

一般使用方法

595b23dc363683fe7e160a4f4bc1fc7f.png

会列出一些功能,包括package下面各个类的概览,及各个功能导航

2、点击页面的堆内存统计

192950a832ee8f4ccbd0c6f5904c68fd.png

有一个表格,对象类型,实例个数,实例所占用内存大小,哪种类型的对象占用了内存最多一目了然

3、点击其中认为内存消耗太多的类名查看类详情

8e86af6431e4dac2fa4f04408016d0d6.png

主要展现该类下面各个实例的大小,以及一些链接导航

4、点击references summary by type

fadac209e247750c28a7dca2908e0d92.png

如果某种类型的对象太多,那么有可能是引用它的那个类的对象太多

基本上一些简单页面的查询,结合原代码,就可以初步定位内存泄漏的地方

综上,dump文件结构还是比较简单的,这对于分析线程的执行情况非常有用,也是每一个Java程序员必须掌握的高级技能之一,你学会了吗?

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/426152.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

GAN 的推导、证明与实现。

转自机器之心整理的,来自Goodfellow 在 NIPS 2016 的演讲和台大李弘毅的解释,完成原 GAN 的推导、证明与实现。 本文主要分四部分,第一部分描述 GAN 的直观概念,第二部分描述概念与优化的形式化表达,第三部分将对 GAN …

玩转oracle 11g(32):plsql版本低需到配置文件中添加配置

1创建了一个数据库geyao,但是只能显示docare 2plsql版本太低,或者直接修改 C:\app\MDSD\product\11.2.0\dbhome_2\NETWORK\ADMIN 添加配置文件 出现歌谣

[测试智能合约]ganache+metamask+remix

1.谷歌浏览器 下载metamask 2.设置metamask 增加一个7545端口的网络 3.导入账户 从ganache的accounts里面随便找个账户的私钥传进去 4.打开remix 修改environment 5.写好的智能合约编译 remix经常抽风 疯狂来回切换版本号或者换网络 6.黄色按钮Deploy 7.同一页面最下方 打开部署…

Newtonsoft.Json反序列化(Deserialize)出错:Bad JSON escape sequence

使用Newtonsoft.Json反序列化收到的字串为JObject或其它支持的数据模型,有时错误,提示如下: Bad JSON escape sequence: \c. Path idno, line 5, position 34. 甚纳闷之。遂搜索资料,略有小获,其非法分界符所致。合法的…

玩转oracle 11g(33):无监听程序

故意操作删除监听 直接配置监听即可

mysql安装条款_mysql 安装注意

mysql 远程连接赋予权限:GRANT ALL PRIVILEGES ON *.* TO root% IDENTIFIED BY datech WITH GRANT OPTION;FLUSH PRIVILEGES;MySQL 5.1采用了基于密码混编算法的鉴定协议,它与早期客户端(4.1之前)使用的协议不兼容。如果你将服务器升级到4.1之上&#xf…

java学习(126):throw向上抛出异常

//throw抛出异常 import java.util.Scanner; public class test66{static class A {void d() throws Exception {int a, b, c;Scanner in new Scanner(System.in);System.out.println("亲输入a的值");a in.nextInt();System.out.println("请输入b的值");…

[Java]集合的小抄 Java初学者必备

文章目录【背景】CollectionsListArrayList优势操作劣势操作LinkedList优势劣势最基本的两种检索集合中的所有对象的方法:CopyOnWriteArrayList补充说明StackMapMap 的常用方法:HashMapLinkedHashMapTreeMapConcurrentHashMapConcurrentSkipListMap补充说…

git之项目上传

git之项目上传 需求:将项目代码上传至github 前期准备: 1.github账号注册 2.安装git环境,可以打开且使用git shell. 3.生成SSH key并与github账号绑定 步骤: 1.进入gitshell 2. 进入到项目指定的目录下,适用git命令初始…

玩转oracle 11g(36):rman备份-控制文件丢失恢复

ORA-00205: error in identifying control file, check alert log for more info 检查oracle的报警日志包含类似报错: ORA-00210: cannot open the specified control file ORA-00202: control file: D:\ORACLE\PRODUCT\10.2.0\ORADATA\DOCARE\C ONTROL01.CTL OR…

[Leedcode][JAVA]第[945]题

【问题描述】 给定整数数组 A,每次 move 操作将会选择任意 A[i],并将其递增 1。返回使 A 中的每个值都是唯一的最少操作次数。示例 1:输入:[1,2,2] 输出:1 解释:经过一次 move 操作,数组将变为 [1, 2, 3]。…

玩转oracle 11g(37):rman备份-数据库指定文件恢复

.数据库指定数据文件恢复 启动数据库的时候报错 ORA-01157: cannot identify/lock data file 5 - see DBWR trace file ORA-01110: data file 5: D:\ORACLE\PRODUCT\10.2.0\ORADATA\DOCARE\AP MEDCOMM.DBF ORA-27041: unable to open file OSD-04002: 无法打开文件 O/S-Erro…

并发编程-concurrent指南-原子操作类-AtomicBoolean

类AtomicBoolean 可以用原子方式更新的 boolean 值。有关原子变量属性的描述,请参阅 java.util.concurrent.atomic 包规范。AtomicBoolean 可用在应用程序中(如以原子方式更新的标志),但不能用于替换 Boolean。 2.构造函数 1.Atom…

[剑指offer]面试题第[7]题[JAVA][斐波那契数列][递归]

【问题描述】 大家都知道斐波那契数列&#xff0c;现在要求输入一个整数n&#xff0c;请你输出斐波那契数列的第n项&#xff08;从0开始&#xff0c;第0项为0&#xff09;。 n<39 【解答思路】 1.递归&#xff08;面试避免&#xff09; O(n^2) public class Solution {pu…

玩转oracle 11g(38):rman备份-全库恢复

(1)选择“开始” “运行”&#xff0c;输入cmd&#xff0c;按回车。 (2)输入“ set oracle_sidorcl”&#xff0c;按回车。 &#xff08;oracle_sid根据自己库的设置写&#xff09; (3)输入“rman target /”&#xff0c;按回车 (4)关闭数据库。输入“shutdown immediate;”…

Django补充

django页面渲染具体流程 在django的页面渲染中&#xff0c;下面这段程序 def test1(request):return render(request,aa.html,{data:wusir}) 等同于 from django.template import loader def test1(request):html loader.get_template(aa.html)html_str html.render({data:wu…

算法复杂度-BigO表示法

1.时间复杂度--大O表示法 算法的渐进时间复杂度&#xff0c;T(n)O(f(n)) T&#xff08;n&#xff09;表示算法的渐进时间复杂度 f&#xff08;n&#xff09;表示代码执行的次数 O&#xff08;&#xff09;表示正比例关系 2.常用的时间复杂度量级 3.举例 &#xff08;1&am…

玩转oracle 11g(40):Oracle11g 不区分大小写设定

Cmd>sqlplus / as sysdba Sql>show  parameter sec_case_sensitive_logon parameter sec_case_sensitive_logon的值为“true”说明区分大小写&#xff0c;为“false”说明不区分大小写&#xff0c;当为“true”时执行以下语句 ALTER SYSTEM SET SEC_CASE_SENSITIVE_…