虚拟机堆转储快照生成以及分析
来源:互联网 发布:升级淘宝网2017新版本 编辑:程序博客网 时间:2024/05/16 23:54
通过程序生成的dump文件来分析故障原因所在。本文给大家展示堆转储快照生成以及分析过程。
第一种:使用暴力手段来生成dump文件— -XX:+HeapDumpOnOutOfMemoryError参数
测试的类如下:
import java.util.*;public class Test{ public static void main(String[] args) throws Exception{ List<TestObject> list=new ArrayList<TestObject>(); while(true){ list.add(new TestObject()); } } static class TestObject{}}
测试之前分析:这是个死循环,程序内存肯定不够用,因为他一直没有释放,所以肯定会报错。
运行此程序:
E:\javatest\test>java -Xms20M -Xmx20M -Xmn10M -XX:+HeapDumpOnOutOfMemoryError Testjava.lang.OutOfMemoryError: Java heap spaceDumping heap to java_pid9900.hprof ...Heap dump file created [29679220 bytes in 0.413 secs]Exception in thread "main" java.lang.OutOfMemoryError: Java heap space at java.util.Arrays.copyOf(Unknown Source) at java.util.Arrays.copyOf(Unknown Source) at java.util.ArrayList.grow(Unknown Source) at java.util.ArrayList.ensureExplicitCapacity(Unknown Source) at java.util.ArrayList.ensureCapacityInternal(Unknown Source) at java.util.ArrayList.add(Unknown Source) at Test.main(Test.java:6)
其中设置此虚拟机的堆初始值xms和最大值xmx相同,防止他自动扩建,xmn参数是指分配新生代大小。
自动生成的dump文件java_pid9900.hprof.打开此hprof文件:
若有时dump文件很大,需要设置jhat参数:jhat -J-Xmx2048m <heap dump file>,但是默认情况下是1024m。
E:\javatest\test>jhat java_pid9900.hprofReading from java_pid9900.hprof...Dump file created Sun Aug 03 15:58:32 CST 2014Snapshot read, resolving...Resolving 1262585 objects...Chasing references, expect 252 dots..........................................................................................................Eliminating duplicate references..........................................................................................................Snapshot resolved.Started HTTP server on port 7000Server is ready.
默认端口号是7000,可以-port 指定端口号,打开7000端口:
其中jhat的dump文件的结构如上。对于最后对象查询语言执行,请参考博客http://blog.csdn.net/gtuu0123/article/details/6039592
上文是通过jhat命令打开访问dump文件,另外一种形式,是通过eclipse或myeclipse插件MAT来访问dump文件。
插件地址:http://www.eclipse.org/mat/downloads.php
其中下载下来,至于安装,大家根据插件安装方式,eclipse或myeclipse其实是一样,其中我都喜欢手动安装插件,使用link方式。
本文测试是myeclipse10.7.1,mat插件1.2.1.
上文是通过dos运行的,并且java运行时配置运行参数,根据上文的配置参数,在IDE中同样配置:
打开hprof文件,File—Open:
选择打开的report:
打开后,刷新refresh项目,项目下会生成一系列文件:
默认打开的Leak report:
Leak Report:内存泄露报告。既然有泄露图,则说明程序中存在内存泄露。先解释一下内存泄露和内存溢出区别。
内存溢出:可以这样理解,对象处于存活状态,然而内存分配不够,对于这种状况,需要检查代码对象生命周期。
内存泄露:针对溢出而言,GC无法回收对象,对象占用内存无法释放。既然提到GC无法回收对象,那就应该理解GC是如何回收对象的,在此简单通俗而言,GC会从root 引用链向下检查回收,被root引用链指向的对象都可以自动回收。但是若内存中存在这样两个对象,互相引用,而两个对象都没有被root引用(直接或间接),那么GC是无法检测到这种引用状况,因此会产生内存泄露。所以,对于内存泄露来说,内存中对象状态不一定是死亡状态。
根据Leak Report图,发现总共Total堆大小14.3(我设置了xms和xmx都是20m,不知为啥total是14.3而非20m,并且通过Problem suspect1中main占用大小,可以得知,这个图大小是个股估值而非精确值)
总共堆大小14.3m,其中a占用13.9m,剩下363b,那我们继续看a的占用情况。
a区域Problem Suspect1当前线程main方法占用97.51%,继续查看detail信息:
Shortest Path to the accumulated point:最短距离到聚集点
main线程的Shallow Heap104b,而Retained Heap14m。
堆积的对象图中:class main下有个Object[]类,其中Shallow Heap4m,而Retained Heap14m。并且Object[]引用的类就是咱们程序中定义的TestObject空静态类了。其中TestObject类的Shallow Heap8b,Retained Heap也是8b。
并且Accumulated Object by Class中,TestObject对象达到1,215,487个,占用堆大小9,723,896字节。
对于以上信息中经常提到Shallow Heap大小和Retained Heap大小,在此解释一下其含义。
Shallow Heap:对象自身占用的大小。不包括引用的对象。
Retained Heap:是指当对象本身被GC后,Heap上共释放的大小。其中Retained Heap=自身占用大小(Shallow Heap)+当前对象直接引用或间接引用的对象的大小。
Shallow Heap和Retained Heap官网英文地址:http://help.eclipse.org/luna/index.jsp?topic=/org.eclipse.mat.ui.help/welcome.html
既然了解到Shallow Heap和Retained Heap含义,那上文的TestObject为啥Shallow Heap=8B。那就要了解内存堆中一个对象如何存放的。
一个对象格式=A+B+C+D;
A:对象头:占用很少信息,描述Object当前状态,在Hot Spot虚拟机中,一个普通对象,占用8 bytes;数组,占用 12 bytes,包含普通对象的 8 bytes + 4 bytes(数组长度)
B:基本类型:boolean、byte 占用 1 byte,char、short 占用 2 bytes,int、float 占用 4 bytes,long、double 占用 8 bytes
C: 引用类型:4 bytes
D:填充物,在Hotspot中,每个对象占用的总空间是以8的倍数计算的,对象占用总空间(对象头+声明变量)不足8的倍数时候,自动补齐。而,这些被填充的空间,我们可以称它为“填充物”。
TestObject中就是一个空类,所以只有8bytes。
若TestObject类中有一个String name属性,则占用大小=对象头8bytes+引用类型4bytes
若TestObject类中有一个boolean isRead属性,则占用大小=对象头8bytes+boolean基本类型1byes(因为是9bytes,不是8的倍数,所以需要补齐,因此填充物=7bytes)+7bytes填充物
若TestObject类中有一个String name属性,一个int age属性,则占用大小=对象头8bytes+name属性4bytes+age属性4bytes=16bytes
除了上文中的Leak Report,mat中还有很多视图,打开i-Overview概要
这是通过参数生成的dump文件,那第二种形式则通过优雅方式jmap方式。
第二种方式:jmap生成dump文件:
jmap查看堆情况:
e:\commonsoftware\jdk1.7\bin>jps7892 Jps10588 Test9372e:\commonsoftware\jdk1.7\bin>jmap -heap 10588Attaching to process ID 10588, please wait...Debugger attached successfully.Client compiler detected.JVM version is 24.65-b04using thread-local object allocation.Mark Sweep Compact GCHeap Configuration: MinHeapFreeRatio = 40 MaxHeapFreeRatio = 70 MaxHeapSize = 20971520 (20.0MB) NewSize = 10485760 (10.0MB) MaxNewSize = 10485760 (10.0MB) OldSize = 4194304 (4.0MB) NewRatio = 2 SurvivorRatio = 8 PermSize = 12582912 (12.0MB) MaxPermSize = 67108864 (64.0MB) G1HeapRegionSize = 0 (0.0MB)Heap Usage:New Generation (Eden + 1 Survivor Space): capacity = 9437184 (9.0MB) used = 745360 (0.7108306884765625MB) free = 8691824 (8.289169311523438MB) 7.898118760850695% usedEden Space: capacity = 8388608 (8.0MB) used = 745360 (0.7108306884765625MB) free = 7643248 (7.2891693115234375MB) 8.885383605957031% usedFrom Space: capacity = 1048576 (1.0MB) used = 0 (0.0MB) free = 1048576 (1.0MB) 0.0% usedTo Space: capacity = 1048576 (1.0MB) used = 0 (0.0MB) free = 1048576 (1.0MB) 0.0% usedtenured generation: capacity = 10485760 (10.0MB) used = 0 (0.0MB) free = 10485760 (10.0MB) 0.0% usedPerm Generation: capacity = 12582912 (12.0MB) used = 153872 (0.1467437744140625MB) free = 12429040 (11.853256225585938MB) 1.2228647867838542% used11722 interned Strings occupying 908888 bytes.
jmap生成bin文件,格式如下:
E:\commonsoftware\jdk1.7\bin>jps93726248 Test12268 JpsE:\commonsoftware\jdk1.7\bin>jmap -F -dump:format=b,file=testtestdump.bin 6248Attaching to process ID 6248, please wait...Debugger attached successfully.Client compiler detected.JVM version is 24.65-b04Dumping heap to testtestdump.bin ...Heap dump file created
解释:在dos下运行,运行很快,jps还没捕捉到pid呢,java已经运行完毕,如何办呢,java方法如何监控呢,无论使用纯文本jmap还是可视化的jconsole,都需要一个pid,其实在方法中先让程序sleep一会,然后捕捉到pid,再进行监控。
import java.util.*;public class Test{ public static void main(String[] args) throws Exception{ Thread.sleep(20000); List<TestObject> list=new ArrayList<TestObject>(); while(true){ list.add(new TestObject()); } } static class TestObject{}}
工欲善其事必先利其器,方可事半功倍。
参考文献:http://www.cnblogs.com/AloneSword/p/3821569.html
http://blog.csdn.net/jiangtongcn/article/details/8222685
2 0
- 虚拟机堆转储快照生成以及分析
- jhat:虚拟机堆转储快照分析工具
- linux中虚拟机的管理以及虚拟机快照的创建
- 虚拟机快照
- 漏洞分析----非常给力的方法----虚拟机快照
- vmware使用虚拟机快照
- xen虚拟机快照
- KVM虚拟机快照
- KVM虚拟机快照备份
- kvm虚拟机快照备份
- 虚拟机 snap 快照
- 关于虚拟机快照
- kvm+libvirt虚拟机快照
- yum rpm 虚拟机快照
- 虚拟机安装与快照
- 创建虚拟机快照
- 虚拟机管理和虚拟机快照
- 虚拟机的安装 虚拟机快照
- 绝对不容错过的全球开发人员搞怪代码注释集锦 极客标签 - 做最棒的极客知识分享平台
- hdu1702 STL的模拟,
- [水]ZOJ1188
- BestCoder Round #3
- easyUI中的layout
- 虚拟机堆转储快照生成以及分析
- Description Resource Path Location Type Java compiler level does not match the version of the insta
- UVa 11877 - The Coco-Cola Store
- hdu 1709 The Balance
- Cocos2d-x中播放背景音乐
- 通知传值
- C中修饰符restrict 的用法
- 【开源夏令营】PFIF公益寻人平台(四)
- QT:在QTableView中使用各种自定义委托