如何用MAT分析Android程序的内存泄露的测试c程序

使用Android Studio + 基于Eclipse的MAT 对Android应用进行内存泄漏的分析和检测 - Android移动开发 - CSDN博客
使用Android Studio + 基于Eclipse的MAT 对Android应用进行内存泄漏的分析和检测
性能检测分析与处理
刚来到北京进行面试的第一家公司,HR 问了一个问题:关于安卓开发过程中对性能分析和内存泄漏有没有接触过,使用过什么工具?其实,一句话问着我了。因为我之前上班的公司都是创业型公司,开发效率最重要!因为boss需要利用成品去拉投资,所以对于程序的内存泄漏和性能的分析还真的是没有接触过。但是同一个坑总不能跌进去两次,因此我就恶补了三个钟头接触了一下并借助之前的项目进行了一下检测和分析并进行了调整和优化,效果真的挺好;
本篇博客先什么也不多说,就是分析一下怎么使用!
首先你要使用Android Studio 安装你的项目到手机上,然后按照上图点击(1)Android Monitor 。这时会显示性能图形的展示界面,我们这时候能看到 Memory 内存耗得是很严重的(这是经过我三个页面快速的打开关闭进行测试的);然后点击一下(2)强制进行GC(每隔几秒钟gc一下),我们可以看到内存释放了了好多,说明有问题存在!然后点击(3)生成快照 .hprof 文件。如下图所示:
图中(1)就是快照文件;这时需要进行分析一下,查找到底是哪里出现了内存的泄露,点击(2)展开,如下图:
然后再点击绿色按钮,就能看到分析的结果,如下图:
其中,(1)就是分析的结果。展开Leaked Activities 我们可以看到都是那些类出现了内存泄漏,这样就很好的为我们指明了方向。接下来我们点击(2)可以查看我们生成的Java Heap 文件列表 快照Fiels:Heap Snapshot,如下图:
然后我们要右击选择&Export to standard .hprof& 生成 &.hprof 文件使用基于Eclipse的 &打开,进行更详细的分析。他的使用方式和Eclipse相似,我们一起看一下:
上面就是分析的图表,如果我们想要更精准的定位分析,这时我们可点击下图中 snapeshot.hprof 下工具栏中的柱状图图标 按钮然后就能切换到下图页面:
这时,我们根据上面的图四所分析的内存泄漏 Leaked Activitys 列表下的Activity-WaitPermissActivity ,在(1)位置输入这个Activity的名字然后回车 就能搜索到。然后右击选择(2)、(3)就能精确进入到该Activity的具体分析展示。
最后,我们可以看到在这个WaitPermissActivity类中出现的内存泄漏问题原因了吧?!他的问题就是这个类依赖的一个广播导致的内存泄漏。然后结合代码发现这个广播是全局的并且是在配置文件 Manefests 中进行静态注册的,广播功能是检测当前的应用网络状态,对某些页面若随时发生网络断开、连接的状态与用户进行交互反馈。因此发现问题有两个,一就是NetBroadcastReceiver这个广播没有反注册;而是广播接收其中的容器的容量一直在增加,没有及时的释放;然后我就根据这两点,把之前的静态注册改换为动态的注册方便控制,并在使用到的Activity和Fragment中进行注册和反注册及释放容器;然后进行修改并再次进行内存的泄露检测,问题都已成功解决!
我的热门文章Android Studio和MAT结合使用来分析内存问题
挥着翅膀的鱼
Android开发中时常会遇到内存泄漏的问题,而Android系统对单个App又有一定的内存限制,此值可以通过一下方式获取:ActivityManager am = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);int memoryClass = am.getMemoryClass();上述代码中momeryClass的值可以当做每个App的内存限制。这个值根据不同的设备厂商都是不一样的,比如我的模拟器的值是32M,如果在我的模拟器上运行的一个App,分配的内存空间超过32M,则会报OOM(内存溢出)!而内存泄漏也是一个导致内存溢出的隐患,因此必须掌握解决内存溢出的方法。本章主要讲解使用Android Studio查看是否有内存泄漏问题,然后使用MAT(Memory Analyzer Tool)来分析并解决内存泄漏问题。Android Studio分析是否有内存泄漏打开Android Studio中的Android Monitor中的Memory面板,可以看到有一个实时变化的堆内存曲线图,如下图所示上图中重点列出了3部分内容:1.被测试的终端设置,如图所示我是在模拟器Nexus_S上做测试2.被测试的进程,点击可选择其他Application或者进程3.当前被测试的进程中内存分配情况Allocated代表已分配的空间Free代表可用剩余空间Allocated + Free不能超App内存限制(32M)4.内存分析的工具栏,从上向下一共4个按钮,依次是:
里约奥运会真是一点不让人省心啊。据外媒报道,当地时间9日里约女子双人十米跳水决赛中,原本清澈湛蓝的水慢慢变成了绿色。
&来源:环球网
文章来源:蝌蚪五线谱耶鲁大学和辛辛那提儿童医院的科学家星期一在《新研究》网站上公布的报告中说,在早期哺乳动物中...
&来源:新浪科技
南极熊刚刚报道了深圳美女创客“SexyCyborg”(性感半机械人)亲身为大家演示3D打印工作流程。
&来源:南极熊3d打印网
谁也没想到,29岁英国美女模特夏洛特·汤普森(Charlotte Thomson)还有这么强的动手能力。
&来源:凤凰网
在为这组名为《Couple Jam》的浴缸摄影集以及此前广受欢迎的《肉·恋》(Flesh Love)摄影作品寻找拍摄对象时...
&来源:凤凰网
OFweek机器人网讯:去年,东莞拥有智能装备制造企业400多家,实施“机器换人”申报项目831个。
&来源:OFweek光电新闻网
如今的智能手机总是讲究性价比,消费者对于超过五千元的手机就会持谨慎购买的态度,当然iPhone除外...
&来源:TV全网通
WiFi越用越慢有时候真想砸了它有人认为是WiFi盒子有问题但其实与路由器的错误摆放也是有关系的有人却不以为然但事实上这...
&来源:燕赵都市报
有消息称索尼大法的下一代智能旗舰智能手机会在明年年初的CES消费电子展上登场。虽然其在配置上的创新提升亮点不多...
&来源:酷玩
节省用电也有妙招,让你的电费省一半!赶紧往下看!!空调 1、空调不宜调的过低夏季空调温度设置在26℃左右为宜...
&来源:品读人生
财大气粗的腾讯真的会在乎微信提现收费那点费用吗?有多少人不相信微信提现收费是为了成本的问题。微信在提现收费前,势必经过了深思熟虑。
&来源:钱庄王员外
8月9日,光音网络发布公告,将投资上海链链文化传媒有限公司,以增强自媒体资源,夯实旗下广告家的场景社群营销平台资源实力...
&来源:携景财富网
Ctrl+D&将本页面保存为书签,全面了解最新资讯,方便快捷。前言的前言:本文是自2005年8月以来,首次在一个月之内发布三篇文章。谨以此文献给这么多年始终不济的我。所谓少不入川,而今已非年少。北漂快两年了,何时能回到故乡,回去后又会怎样,也许永远是个未知……
在平时工作过程中,有时会遇到OutOfMemoryError,我们知道遇到Error一般表明程序存在着严重问题,可能是灾难性的。所以找出是什么原因造成OutOfMemoryError非常重要。现在向大家引荐Eclipse Memory Analyzer tool(MAT),来化解我们遇到的难题。如未说明,本文均使用Java 5.0 on Windows XP SP3环境。
之前的观点,我认为使用实时profiling/monitoring之类的工具,用一种非常实时的方式来分析哪里存在内存泄漏是很正确的。年初使用了某profiler工具测试消息中间件中存在的内存泄漏,发现在吞吐量很高的时候profiler工具自己也无法响应,这让人很头痛。后来了解到这样的工具本身就要消耗性能,且在某些条件下还发现不了泄漏。所以,分析离线数据就非常重要了,MAT正是这样一款工具。
为何会内存溢出
我们知道JVM根据generation(代)来进行GC,根据下图所示,一共被分为young generation(年轻代)、tenured generation(老年代)、permanent generation(永久代, perm gen),perm gen(或称Non-Heap 非堆)是个异类,稍后会讲到。注意,heap空间不包括perm gen。
绝大多数的对象都在young generation被分配,也在young generation被收回,当young generation的空间被填满,GC会进行minor collection(次回收),这次回收不涉及到heap中的其他generation,minor collection根据weak generational hypothesis(弱年代假设)来假设young generation中大量的对象都是垃圾需要回收,minor collection的过程会非常快。young generation中未被回收的对象被转移到tenured generation,然而tenured generation也会被填满,最终触发major collection(主回收),这次回收针对整个heap,由于涉及到大量对象,所以比minor collection慢得多。
JVM有三种垃圾回收器,分别是throughput collector,用来做并行young generation回收,由参数-XX:+UseParallelGC启动;concurrent low pause collector,用来做tenured generation并发回收,由参数-XX:+UseConcMarkSweepGC启动;incremental low pause collector,可以认为是默认的垃圾回收器。不建议直接使用某种垃圾回收器,最好让JVM自己决断,除非自己有足够的把握。
Heap中各generation空间是如何划分的?通过JVM的-Xmx=n参数可指定最大heap空间,而
则是指定最小heap空间。在JVM初始化的时候,如果最小heap空间小于最大heap空间的话,如上图所示JVM会把未用到的空间标注为Virtual。除了这两个参数还有-XX:MinHeapFreeRatio=n和 -XX:MaxHeapFreeRatio=n来分别控制最大、最小的剩余空间与活动对象之比例。在32位Solaris SPARC操作系统下,默认值如下,在32位windows xp下,默认值也差不多。
MinHeapFreeRatio
MaxHeapFreeRatio
由于tenured generation的major collection较慢,所以tenured generation空间小于young generation的话,会造成频繁的major collection,影响效率。Server JVM默认的young generation和tenured generation空间比例为1:2,也就是说young generation的eden和survivor空间之和是整个heap(当然不包括perm gen)的三分之一,该比例可以通过-XX:NewRatio=n参数来控制,而Client JVM默认的-XX:NewRatio是8。至于调整young generation空间大小的NewSize=n和MaxNewSize=n参数就不讲了,请参考后面的资料。
young generation中幸存的对象被转移到tenured generation,但不幸的是concurrent collector线程在这里进行major collection,而在回收任务结束前空间被耗尽了,这时将会发生Full Collections(Full GC),整个应用程序都会停止下来直到回收完成。Full GC是高负载生产环境的噩梦……
现在来说说异类perm gen,它是JVM用来存储无法在Java语言级描述的对象,这些对象分别是类和方法数据(与class loader有关)以及interned strings(字符串驻留)。一般32位OS下perm gen默认64m,可通过参数-XX:MaxPermSize=n指定,
一文说,对于这块区域,没有更详细的文献了,神秘。
回到问题“为何会内存溢出?”。
要回答这个问题又要引出另外一个话题,既什么样的对象GC才会回收?当然是GC发现通过任何reference chain(引用链)无法访问某个对象的时候,该对象即被回收。名词GC Roots正是分析这一过程的起点,例如JVM自己确保了对象的可到达性(那么JVM就是GC Roots),所以GC Roots就是这样在内存中保持对象可到达性的,一旦不可到达,即被回收。通常GC Roots是一个在current thread(当前线程)的call stack(调用栈)上的对象(例如方法参数和局部变量),或者是线程自身或者是system class loader(系统类加载器)加载的类以及native code(本地代码)保留的活动对象。所以GC Roots是分析对象为何还存活于内存中的利器。知道了什么样的对象GC才会回收后,再来学习下对象引用都包含哪些吧。
从最强到最弱,不同的引用(可到达性)级别反映了对象的生命周期。
Strong Ref(强引用):通常我们编写的代码都是Strong Ref,于此对应的是强可达性,只有去掉强可达,对象才被回收。
Soft Ref(软引用):对应软可达性,只要有足够的内存,就一直保持对象,直到发现内存吃紧且没有Strong Ref时才回收对象。一般可用来实现缓存,通过java.lang.ref.SoftReference类实现。
Weak Ref(弱引用):比Soft Ref更弱,当发现不存在Strong Ref时,立刻回收对象而不必等到内存吃紧的时候。通过java.lang.ref.WeakReference和java.util.WeakHashMap类实现。
Phantom Ref(虚引用):根本不会在内存中保持任何对象,你只能使用Phantom Ref本身。一般用于在进入finalize()方法后进行特殊的清理过程,通过 java.lang.ref.PhantomReference实现。
有了上面的种种我相信很容易就能把heap和perm gen撑破了吧,是的利用Strong Ref,存储大量数据,直到heap撑破;利用interned strings(或者class loader加载大量的类)把perm gen撑破。
shallow size
retained size
Shallow size就是对象本身占用内存的大小,不包含对其他对象的引用,也就是对象头加成员变量(不是成员变量的值)的总和。在32位系统上,对象头占用8字节,int占用4字节,不管成员变量(对象或数组)是否引用了其他对象(实例)或者赋值为null它始终占用4字节。故此,对于String对象实例来说,它有三个int成员(3*4=12字节)、一个char[]成员(1*4=4字节)以及一个对象头(8字节),总共3*4 +1*4+8=24字节。根据这一原则,对String a=”rosen jiang”来说,实例a的shallow size也是24字节(很多人对此有争议,请看官甄别并留言给我)。
Retained size是该对象自己的shallow size,加上从该对象能直接或间接访问到对象的shallow size之和。换句话说,retained size是该对象被GC之后所能回收到内存的总和。为了更好的理解retained size,不妨看个例子。
把内存中的对象看成下图中的节点,并且对象和对象之间互相引用。这里有一个特殊的节点GC Roots,正解!这就是reference chain的起点。
从obj1入手,上图中蓝色节点代表仅仅只有通过obj1才能直接或间接访问的对象。因为可以通过GC Roots访问,所以左图的obj3不是蓝色节点;而在右图却是蓝色,因为它已经被包含在retained集合内。
所以对于左图,obj1的retained size是obj1、obj2、obj4的shallow size总和;右图的retained size是obj1、obj2、obj3、obj4的shallow size总和。obj2的retained size可以通过相同的方式计算。
heap dump是特定时间点,java进程的内存快照。有不同的格式来存储这些数据,总的来说包含了快照被触发时java对象和类在heap中的情况。由于快照只是一瞬间的事情,所以heap dump中无法包含一个对象在何时、何地(哪个方法中)被分配这样的信息。
在不同平台和不同java版本有不同的方式获取heap dump,而MAT需要的是HPROF格式的heap dump二进制文件。想无需人工干预的话,要这样配置JVM参数:-XX:-HeapDumpOnOutOfMemoryError,当错误发生时,会自动生成heap dump,在生产环境中,只有用这种方式。如果你想自己控制什么时候生成heap dump,在Windows+JDK6环境中可利用JConsole工具,而在Linux或者Mac OS X环境下均可使用JDK5、6自带的jmap工具。当然,还可以配置JVM参数:-XX:+HeapDumpOnCtrlBreak,也就是在控制台使用Ctrl+Break键来生成heap dump。由于我是windows+JDK5,所以选择了-XX:-HeapDumpOnOutOfMemoryError这种方式,更多配置请参考
前言的前言
写blog就是好,在大前提下可以想说什么写什么,不像投稿那么字字斟酌。上周末回了趟成都办事,所以本文来迟了。K117从达州经由达成线往成都方向走的时候,发现铁路边有条河,尽管我现在也不知道其名字,但已被其深深的陶醉。河很宽且水流平缓,河边山丘森林密布,民房星星点点的分布在河边,河里偶尔些小船。当时我就在想,在这里生活是多么的惬意,夏天还可以下去畅游一番,闲来无事也可垂钓。唉,越来越讨厌北漂了。
中,我介绍了内存泄漏的前因后果。在本文中,将介绍MAT如何根据heap dump分析泄漏根源。由于测试范例可能过于简单,很容易找出问题,但我期待借此举一反三。
一开始不得不说说ClassLoader,本质上,它的工作就是把磁盘上的类文件读入内存,然后调用java.lang.ClassLoader.defineClass方法告诉系统把内存镜像处理成合法的字节码。Java提供了抽象类ClassLoader,所有用户自定义类装载器都实例化自ClassLoader的子类。system class loader在没有指定装载器的情况下默认装载用户类,在Sun Java 1.5中既sun.misc.Launcher$AppClassLoader。更详细的内容请参看下面的资料。
准备heap dump
请看下面的Pilot类,没啥特殊的。
* Pilot class
* @author rosen jiang
package org.rosenjiang.
public class Pilot{
public Pilot(String a, int b){
然后再看OOMHeapTest类,它是如何撑破heap dump的。
* OOMHeapTest class
* @author rosen jiang
package org.rosenjiang.
import java.util.D
import java.util.HashM
import java.util.M
import org.rosenjiang.bo.P
public class OOMHeapTest {
public static void main(String[] args){
private static void oom(){
Map&String, Pilot& map = new HashMap&String, Pilot&();
Object[] array = new Object[1000000];
for(int i=0; i&1000000; i++){
String d = new Date().toString();
Pilot p = new Pilot(d, i);
map.put(i+&rosen jiang&, p);
array[i]=p;
是的,上面构造了很多的Pilot类实例,向数组和map中放。由于是Strong Ref,GC自然不会回收这些对象,一直放在heap中直到溢出。当然在运行前,先要在Eclipse中配置VM参数-XX:+HeapDumpOnOutOfMemoryError。好了,一会儿功夫内存溢出,控制台打出如下信息。
java.lang.OutOfMemoryError: Java heap space
Dumping heap to java_pid3600.hprof
Heap dump file created [ bytes in 1.995 secs]
Exception in thread &main& java.lang.OutOfMemoryError: Java heap space
java_pid3600.hprof既是heap dump,可以在OOMHeapTest类所在的工程根目录下找到。
话分两头说,有了heap dump还得安装MAT。可以在http://www.eclipse.org/mat/downloads.php选择合适的方式安装。安装完成后切换到Memory Analyzer视图。在Eclipse的左上角有Open Heap Dump按钮,按照刚才说的路径找到java_pid3600.hprof文件并打开。解析hprof文件会花些时间,然后会弹出向导,直接Finish即可。稍后会看到下图所示的界面。
MAT工具分析了heap dump后在界面上非常直观的展示了一个饼图,该图深色区域被怀疑有内存泄漏,可以发现整个heap才64M内存,深色区域就占了99.5%。接下来是一个简短的描述,告诉我们main线程占用了大量内存,并且明确指出system class loader加载的&java.lang.Thread&实例有内存聚集,并建议用关键字&java.lang.Thread&进行检查。所以,MAT通过简单的两句话就说明了问题所在,就算使用者没什么处理内存问题的经验。在下面还有一个&Details&链接,在点开之前不妨考虑一个问题:为何对象实例会聚集在内存中,为何存活(而未被GC)?是的——Strong Ref,那么再走近一些吧。
点击了&Details&链接之后,除了在上一页看到的描述外,还有Shortest Paths To the Accumulation Point和Accumulated Objects部分,这里说明了从GC root到聚集点的最短路径,以及完整的reference chain。观察Accumulated Objects部分,java.util.HashMap和java.lang.Object[1000000]实例的retained heap(size)最大,在上一篇文章中我们知道retained heap代表从该类实例沿着reference chain往下所能收集到的其他类实例的shallow heap(size)总和,所以明显类实例都聚集在HashMap和Object数组中了。这里我们发现一个有趣的现象,既Object数组的shallow heap和retained heap竟然一样,通过
一文可知,数组的shallow heap和一般对象(非数组)不同,依赖于数组的长度和里面的元素的类型,对数组求shallow heap,也就是求数组集合内所有对象的shallow heap之和。好,再来看org.rosenjiang.bo.Pilot对象实例的shallow heap为何是16,因为对象头是8字节,成员变量int是4字节、String引用是4字节,故总共16字节。
接着往下看,来到了Accumulated Objects by Class区域,顾名思义,这里能找到被聚集的对象实例的类名。org.rosenjiang.bo.Pilot类上头条了,被实例化了290,325次,再返回去看程序,我承认是故意这么干的。还有很多有用的报告可用来协助分析问题,只是本文中的例子太简单,也用不上。以后如有用到,一定撰文详细叙述。
又是perm gen
我们在上一篇文章中知道,perm gen是个异类,里面存储了类和方法数据(与class loader有关)以及interned strings(字符串驻留)。在heap dump中没有包含太多的perm gen信息。那么我们就用这些少量的信息来解决问题吧。
看下面的代码,利用interned strings把perm gen撑破了。
* OOMPermTest class
* @author rosen jiang
package org.rosenjiang.
public class OOMPermTest {
public static void main(String[] args){
private static void oom(){
Object[] array = new Object[];
for(int i=0; i&; i++){
String d = String.valueOf(i).intern();
array[i]=d;
控制台打印如下的信息,然后把java_pid1824.hprof文件导入到MAT。其实在MAT里,看到的状况应该和“OutOfMemoryError: Java heap space”差不多(用了数组),因为heap dump并没有包含interned strings方面的任何信息。只是在这里需要强调,使用intern()方法的时候应该多加注意。
java.lang.OutOfMemoryError: PermGen space
Dumping heap to java_pid1824.hprof
Heap dump file created [ bytes in 2.845 secs]
Exception in thread &main& java.lang.OutOfMemoryError: PermGen space
倒是在思考如何把class loader撑破废了些心思。经过尝试,发现使用ASM来动态生成类才能达到目的。ASM(http://asm.objectweb.org)的主要作用是处理已编译类(compiled class),能对已编译类进行生成、转换、分析(功能之一是实现动态代理),而且它运行起来足够的快和小巧,文档也全面,实属居家必备之良品。ASM提供了core API和tree API,前者是基于事件的方式,后者是基于对象的方式,类似于XML的SAX、DOM解析,但是使用tree API性能会有损失。既然下面要用到ASM,这里不得不啰嗦下已编译类的结构,包括:
1、修饰符(例如public、private)、类名、父类名、接口和annotation部分。
2、类成员变量声明,包括每个成员的修饰符、名字、类型和annotation。
3、方法和构造函数描述,包括修饰符、名字、返回和传入参数类型,以及annotation。当然还包括这些方法或构造函数的具体Java字节码。
4、常量池(constant pool)部分,constant pool是一个包含类中出现的数字、字符串、类型常量的数组。
已编译类和原来的类源码区别在于,已编译类只包含类本身,内部类不会在已编译类中出现,而是生成另外一个已编译类文件;其二,已编译类中没有注释;其三,已编译类没有package和import部分。
这里还得说说已编译类对Java类型的描述,对于原始类型由单个大写字母表示,Z代表boolean、C代表char、B代表byte、S代表short、I代表int、F代表float、J代表long、D代表double;而对类类型的描述使用内部名(internal name)外加前缀L和后面的分号共同表示来表示,所谓内部名就是带全包路径的表示法,例如String的内部名是java/lang/String;对于数组类型,使用单方括号加上数据元素类型的方式描述。最后对于方法的描述,用圆括号来表示,如果返回是void用V表示,具体参考下图。
下面的代码中会使用ASM core API,注意接口ClassVisitor是核心,FieldVisitor、MethodVisitor都是辅助接口。ClassVisitor应该按照这样的方式来调用:visit visitSource? visitOuterClass? ( visitAnnotation | visitAttribute )*( visitInnerClass | visitField | visitMethod )* visitEnd。就是说visit方法必须首先调用,再调用最多一次的visitSource,再调用最多一次的visitOuterClass方法,接下来再多次调用visitAnnotation和visitAttribute方法,最后是多次调用visitInnerClass、visitField和visitMethod方法。调用完后再调用visitEnd方法作为结尾。
注意ClassWriter类,该类实现了ClassVisitor接口,通过toByteArray方法可以把已编译类直接构建成二进制形式。由于我们要动态生成子类,所以这里只对ClassWriter感兴趣。首先是抽象类原型:
* @author rosen jiang
* MyAbsClass class
package org.rosenjiang.
public abstract class MyAbsClass {
int LESS = -1;
int EQUAL = 0;
int GREATER = 1;
abstract int absTo(Object o);
其次是自定义类加载器,实在没法,ClassLoader的defineClass方法都是protected的,要加载字节数组形式(因为toByteArray了)的类只有继承一下自己再实现。
* @author rosen jiang
* MyClassLoader class
package org.rosenjiang.
public class MyClassLoader extends ClassLoader {
public Class defineClass(String name, byte[] b) {
return defineClass(name, b, 0, b.length);
最后是测试类。
* @author rosen jiang
* OOMPermTest class
package org.rosenjiang.
import java.util.ArrayL
import java.util.L
import org.objectweb.asm.ClassW
import org.objectweb.asm.O
public class OOMPermTest {
public static void main(String[] args) {
OOMPermTest o = new OOMPermTest();
private void oom() {
ClassWriter cw = new ClassWriter(0);
cw.visit(Opcodes.V1_5, Opcodes.ACC_PUBLIC + Opcodes.ACC_ABSTRACT,
&org/rosenjiang/test/MyAbsClass&, null, &java/lang/Object&,
new String[] {});
cw.visitField(Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL + Opcodes.ACC_STATIC, &LESS&, &I&,
null, new Integer(-1)).visitEnd();
cw.visitField(Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL + Opcodes.ACC_STATIC, &EQUAL&, &I&,
null, new Integer(0)).visitEnd();
cw.visitField(Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL + Opcodes.ACC_STATIC, &GREATER&, &I&,
null, new Integer(1)).visitEnd();
cw.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_ABSTRACT, &absTo&,
&(Ljava/lang/O)I&, null, null).visitEnd();
cw.visitEnd();
byte[] b = cw.toByteArray();
List&ClassLoader& classLoaders = new ArrayList&ClassLoader&();
while (true) {
MyClassLoader classLoader = new MyClassLoader();
classLoader.defineClass(&org.rosenjiang.test.MyAbsClass&, b);
classLoaders.add(classLoader);
} catch (Exception e) {
e.printStackTrace();
不一会儿,控制台就报错了。
java.lang.OutOfMemoryError: PermGen space
Dumping heap to java_pid3023.hprof
Heap dump file created [ bytes in 2.405 secs]
Exception in thread &main& java.lang.OutOfMemoryError: PermGen space
打开java_pid3023.hprof文件,注意看下图的Classes: 88.1k和Class Loader: 87.7k部分,从这点可看出class loader加载了大量的类。
更进一步分析,点击上图中红框线圈起来的按钮,选择Java Basics——Class Loader Explorer功能。打开后能看到下图所示的界面,第一列是class loader名字;第二列是class loader已定义类(defined classes)的个数,这里要说一下已定义类和已加载类(loaded classes)了,当需要加载类的时候,相应的class loader会首先把请求委派给父class loader,只有当父class loader加载失败后,该class loader才会自己定义并加载类,这就是Java自己的“双亲委派加载链”结构;第三列是class loader所加载的类的实例数目。
在Class Loader Explorer这里,能发现class loader是否加载了过多的类。另外,还有Duplicate Classes功能,也能协助分析重复加载的类,在此就不再截图了,可以肯定的是MyAbsClass被重复加载了N多次。
其实MAT工具非常的强大,上面故弄玄虚的范例代码根本用不上MAT的其他分析功能,所以就不再描述了。其实对于OOM不只我列举的两种溢出错误,还有多种其他错误,但我想说的是,对于perm gen,如果实在找不出问题所在,建议使用JVM的-verbose参数,该参数会在后台打印出日志,可以用来查看哪个class loader加载了什么类,例:“[Loaded org.rosenjiang.test.MyAbsClass from org.rosenjiang.test.MyClassLoader]”。
相关 [memory analyzer tool] 推荐:
- 移动开发 - ITeye博客
前言的前言:本文是自2005年8月以来,首次在一个月之内发布三篇文章. 谨以此文献给这么多年始终不济的我. 北漂快两年了,何时能回到故乡,回去后又会怎样,也许永远是个未知……. 在平时工作过程中,有时会遇到OutOfMemoryError,我们知道遇到Error一般表明程序存在着严重问题,可能是灾难性的.
《使用MAT(Memory Analyzer Tool)工具分析dump文件》. 生产环境中,尤其是吃大内存的JVM,一旦出现内存泄露等问题是非常容易引发OutofMemory的,如果没有一个好的工具提供给开发人员定位问题和分析问题,那么这将会是一场
噩梦. 目前JDK其实自带有一些内存泄露分析工具专门用于帮助开发人员定位内存泄露等问题,但是这些工具往往并不是能够满足一些现状,这里笔者所指的现状更多是迅速、便捷、高效的定位出问题,方便开发人员迅速进行调整.
- Java - 编程语言 - ITeye博客
Eclipse Memory Analyzer是一个非常棒的堆内存分析工具,是JDK自带的堆分析工具jhat的一个非常好的替代品,能够快速地定位Java内存泄露的原因.
可能有的同学会问,JVM不是号称自动内存管理,GC会自动垃圾回收,Java怎么会有内存泄露,不会搞错吧.
在开始分析之前,我们先想想,在编程这个角度上,我们如何避免堆内存泄露呢.
在平时开发、测试过程中、甚至是生产环境中,有时会遇到OutOfMemoryError,Java堆溢出了,这表明程序有严重的问题. 我们需要找造成OutOfMemoryError原因. 1、内存泄露,对象已经死了,无法通过垃圾收集器进行自动回收,通过找出泄露的代码位置和原因,才好确定解决方案;. 2、内存溢出,内存中的对象都还必须存活着,这说明Java堆分配空间不足,检查堆设置大小(-Xmx与-Xms),检查代码是否存在对象生命周期太长、持有状态时间过长的情况.
- 搜索技术博客-淘宝
最近在用vtune分析程序性能瓶颈时,发现一些内存访问的地方竟然成了cpu热点. 经过仔细分析,发现这些热点主要是对大数组非连续位置的访问的引起的. 比较消耗cpu的原因应该是cache不命中. 因为像这样局部性很差的内存访问逻辑,对cache是很不友好的. 于是想到了prefetch……. x86(以及其他很多体系结构)的CPU提供了prefetch系列指令,用于将指定地址的内存预取到cache.
- sun409 - 阿偉的個人天地
由於八月底發生 kernel.org 被 hacked 的事件,導致 kernel.org 底下的服務全面停擺,包括 Google 的 Android git server android.git.kernel.org,至今仍未恢復. 當然也導致目前無法下載最新的 Android source code.
- CSDN博客数据库推荐文章
通过 SPA,您可以根据各种更改类型(如初始化参数更改、优化器统计刷新和数据库升级)播放特定的. SQL 或整个 SQL 负载,然后生成比较报告,帮助您评估它们的影响.. 在 Oracle Database 11g 之前的版本中,我必须捕获所有 SQL 语句,通过跟踪运行这些语句,. 然后得到执行计划 — 这是一项极其耗时又极易出错的任务.
- chuang - Sailing
有关Cache的思考. 1.1 Cache不可不察也. 第2章
Cache的基础知识. 2.1 Cache的工作原理. 2.2 Cache的组成结构. 2.4 Cache Block的替换算法1. 2.4 Cache Block的替换算法2. 第3章 Coherency and
Consistency.
- Taobao UED Team
这篇文章是根据目前 chrome 稳定版(19.0.1084.52 m)写的, 因为 google 也在不断完善chrome developer tool, 所以 chrome 版本不同可能稍有差别. 一些快捷键也是 windows 上的, mac 下的应该大同小异.. 常规的断点相关的 breakpoint/conditional-breakpoint/call-stack/watch-expressions 等就不涉及了..
- CSDN博客推荐文章
顺便研究了下hibernatetool 发现已经到了4.0beta,我用的是3.2的没有解决oracle的注释问题,4.0已经解决了. 我用maven2创建了一个项目. parent的依赖是我的公共依赖 &project xmlns=&http://maven.apache.org/POM/4.0.0& xmlns:xsi=&http://www.w3.org/2001/XMLSchema-instance&.
坚持分享优质有趣的原创文章,并保留作者信息和版权声明,任何问题请联系:@。

我要回帖

更多关于 内存泄露分析工具 的文章

 

随机推荐