如何定位和解决Andorid的tomcat 内存溢出解决问题

如何定位和解决Andorid的内存溢出问题_百度知道
如何定位和解决Andorid的内存溢出问题
我有更好的答案
第一个项目中由于app加载的图片、报表比较多
其他类似问题
为您推荐:
内存溢出的相关知识
等待您来回答
下载知道APP
随时随地咨询
出门在外也不愁1796人阅读
内存溢出作为软件使用过程中极其不希望看到的难题,一直困扰着软件开发与使用者。当然在报表应用的使用过程中,如果配置或使用不当也会出现内存溢出的问题。出现内存溢出的问题我们要敢于面对,要通过适当的排查方法和相应的解决步骤一步一步找到问题出现的原因并最终解决掉该问题。
本文对使用报表过程中出现内存溢出问题进行简单地分析,给出一些建议性的排查步骤和解决方法。
排查步骤与解决办法
首先我们要判断出现的问题是否是由于内存溢出引起的,典型的后台信息是带有OutOf Memory字样,但是也不排除其他内存溢出的提示,如tomcat内存溢出可出现三种提示信息:Java heap space、PermGen space和unable to create new native thread。而有时线程死锁也会导致应用挂掉。所以我们看到具体出错信息如果判断不出是何种问题,最好上网查询确认一下。
判断是否与报表有关
一般来说,任何应用都可能出现内存溢出,所以当我们确定出现了内存溢出,接下来要做的就是划分区域,判断内存溢出是哪部分引起的。
一般报表应用与客户自己应用相结合的系统出现内存溢出的问题,需要判断该问题是否是由报表引起的?具体方法是单独部署报表应用并执行原操作,看是否会出现内存溢出。若此步骤问题重现,则按照如下步骤进行;否则,可能说明与报表无关,当然也可以按照下面的步骤继续进行排查。
查找问题出现的共性
一般内存溢出不会只出现一次,这就要求我们记录每次出项问题的共性。如:是否访问某张特定报表时出现?是否访问量达到一定程度时出现?是否访问一些大数据量报表时出现?
下面给出在如下情况下的建议设置:
访问某个特定报表时
若我们发现,内存溢出每次均出现在访问系统中某张报表时(一般后台信息也有体现),这时我们就需要拿这张报表看看了,主要查看报表设计是否合理、表达式以及sql语句是否性能极其低下、报表计算是否非常复杂等。
若检查中发现如上问题,需要做如下一步或几步更改:
A、理顺报表设计逻辑,重新设计报表
B、替换性能低下的表达式,如嵌套多层if时可以使用case替代
C、更改性能低下的sql语句
D、报表中如果做了大量的统计、排名等,尽量将其整合到sql中,即简化报表运算
E、使用存储过程做数据集,并是使用order by排序(与报表展现数据顺序相同)
访问某个或某些大数据量报表时
若发现内存溢出均发生在访问某个或某些大数据量报表后出现(可能需要查看后台信息多次确认)。这种情况可以尝试如下解决办法
A、增大jvm,即从内存支持上扩充。不同的应用服务器设置方法不同,但是一定要注意并不是jvm设置越大越好,一般不超过物理内存的30%(建议)。
B、配置reportConfig.xml文件。对于数据量大的情况,润乾提供了“数据量大的配置方案”详见《润乾报表在J2EE下的部署》。一般要减小maxConcurrentForReport和maxCellNum、增大cachedReportTimeout和maxWaitTimeForReport。
C、增大物理内存。这个办法可以作为终极解决方案了。
访问量增加到一定范围时
若访问量达到一定程度就出现内存溢出的情况,可以尝试如下解决办法
A、增大JVM或物理内存
B、增大数据库允许最大连接数
C、增大应用服务器连接池最大连接数
D、配置reportConfig.xml文件。对于访问量高的情况,润乾提供了“访问量高的配置方案”详见《润乾报表在J2EE下的部署》。一般要增大maxConcurrentForReport和maxCellNum、减小cachedReportTimeout和maxWaitTimeForReport。
另外,需要注意:配置数据库允许的最大连接数和应用服务器的连接池个数时,必须大于报表的并发数+报表的等待数。
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:42670次
积分:1017
积分:1017
排名:千里之外
原创:60篇
(4)(4)(4)(4)(5)(5)(2)(3)(4)(9)(4)(10)(2)如何定位和解决Andorid的内存溢出问题(大总结)-爱编程
如何定位和解决Andorid的内存溢出问题(大总结)
转载请备注出自于:http://blog.csdn.net/qq_/article/details/
我们经常在做项目过程中遇到内存溢出的问题,同时面试中关于OOM的问题也常常出现。
这里,我将前辈们解决Andorid内存溢出的方法重新整理一番,方便自己以后使用。
一、Android的内存机制
android应用层是由java开发的,android的davlik虚拟机与jvm也类似,只不过它是基于寄存器的。在java中,通过new为对象分配内存,所有对象在java堆内分配空间;而内存的释放是由垃圾收集器(GC)来回收的。 Java采用了有向图的原理。Java将引用关系考虑为图的有向边,有向边从引用者指向引用对象。线程对象可以作为有向图的起始顶点,该图就是从起始顶点(GC roots)开始的一棵树,根顶点可以到达的对象都是有效对象,GC不会回收这些对象。如果某个对象
(连通子图)与这个根顶点不可达(注意,该图为有向图),那么我们认为这个(这些)对象不再被引用,可以被GC回收。
二、Android的内存溢出原因
1、内存泄露导致
由于我们程序的失误,长期保持某些资源(如Context)的引用,垃圾回收器就无法回收它,当然该对象占用的内存就无法被使用,这就造成内存泄露。
Android&中常见就是Activity被引用在调用finish之后却没有释放,第二次打开activity又重新创建,这样的内存泄露不断的发生,则会导致内存的溢出。
Android的每个应用程序都会使用一个专有的Dalvik虚拟机实例来运行,它是由Zygote服务进程孵化出来的,也就是说每个应用程序都是在属于自己的进程中运行的。Android为不同类型的进程分配了不同的内存使用上限,如果程序在运行过程中出现了内存泄漏的而造成应用进程使用的内存超过了这个上限,则会被系统视为内存泄漏,从而被kill掉,这使得仅仅自己的进程被kill掉,而不会影响其他进程.
2、占用内存较多的对象
保存了多个耗用内存过大的对象(如Bitmap)或加载单个超大的图片,造成内存超出限制。
三、常见的内存泄漏问题及其解决方案
1、引用没释放造成的内存泄露
1.1注册没取消造成的内存泄露
&这种Android的内存泄露比纯Java的内存泄漏还要严重,因为其他一些Android程序可能引用系统的Android程序的对象(比如注册机制)。即使Android程序已经结束了,但是别的应用程序仍然还有对Android程序的某个对象的引用,泄漏的内存依然不能被垃圾回收。
1.2集合中对象没清理造成的内存泄露
我们通常把一些对象的引用加入到了集合中,当我们不需要该对象时,并没有把它的引用从集合中清理掉,这样这个集合就会越来越大。如果这个集合是static的话,那情况就更严重了。
1.3&static
&static是Java中的一个关键字,当用它来修饰成员变量时,那么该变量就属于该类,而不是该类的实例。
&&& private static ActivitymC&&&&&& //省略
如何才能有效的避免这种引用的发生呢?
&&&&第一,应该尽量避免static成员变量引用资源耗费过多的实例,比如Context。
&&&&第二、Context尽量使用ApplicationContext,因为Application的Context的生命周期比较长,引用它不会出现内存泄露的问题。
看使用的周期是否在activity周期内,如果超出,必须用application;常见的情景包括:AsyncTask,Thread,第三方库初始化等等。还有些情景,只能用activity:比如,对话框,各种View,需要startActivity的等。总之,尽可能使用Application。
&&&&第三、使用WeakReference代替强引用。比如可以使用WeakReference&Context&mContextR
1.4、线程(内部类的使用)
线程产生内存泄露的主要原因在于线程生命周期的不可控。如果我们的线程是Activity的内部类,所以MyThread中保存了Activity的一个引用,当MyThread的run函数没有结束时,MyThread是不会被销毁的,因此它所引用的老的Activity也不会被销毁,因此就出现了内存泄露的问题。
如果非静态内部类的方法中,有生命周期大于其所在类的,那就有问题了。比如:AsyncTask、Handler,这两个类都是方便开发者执行异步任务的,但是,这两个都跳出了Activity/Fragment的生命周期。
&&&&第一、将线程的内部类,改为静态内部类。
&&&&&&&原因:
因为非静态内部类会自动持有一个所属类的实例,如果所属类的实例已经结束生命周期,但内部类的方法仍在执行,就会hold其主体(引用)。也就使主体不能被释放,亦即内存泄露。静态类编译后和非内部类是一样的,有自己独立的类名。不会悄悄引用所属类的实例,所以就不容易泄露。
&&&&第二、如果需要引用Acitivity,使用弱引用。
2、资源对象没关闭造成的内存泄露
资源性对象比如(Cursor,File文件等)往往都用了一些缓冲,我们在不使用的时候,应该及时关闭它们,以便它们的缓冲及时回收内存。而不是等待GC来处理。它们的缓冲不仅存在于java虚拟机内,还存在于java虚拟机外。如果我们仅仅是把它的引用设置为null,而不关闭它们,往往会造成内存泄露。因为有些资源性对象,比如SQLiteCursor(在析构函数finalize(),如果我们没有关闭它,它自己会调close()关闭),如果我们没有关闭它,系统在回收它时也会关闭它,但是这样的效率太低了。而且android数据库中对Cursor资源的是又限制个数的,如果不及时close掉,会导致别的地方无法获得。
3、一些不良代码成内存压力
有些代码并不造成内存泄露,但是它们,或是对没使用的内存没进行有效及时的释放,或是没有有效的利用已有的对象而是频繁的申请新内存,对内存的回收和分配造成很大影响的,容易迫使虚拟机不得不给该应用进程分配更多的内存,造成不必要的内存开支。
3.1 Bitmap没调用recycle()
Bitmap对象在不使用时,我们应该先调用recycle()释放内存,然后才设置为null.
虽然recycle()从源码上看,调用它应该能立即释放Bitmap的主要内存,但是测试结果显示它并没能立即释放内存。但是我猜应该还是能大大的加速Bitmap的主要内存的释放。
3.2 构造Adapter时,没有使用缓存的&convertView
&以构造ListView的BaseAdapter为例,在BaseAdapter中提共了方法:
public&View&getView(int&position,&View&convertView,&ViewGroup&parent)
来向ListView提供每一个item所需要的view对象。初始时ListView会从BaseAdapter中根据当前的屏幕布局实例化一定数量的view对象,同时ListView会将这些view对象缓存起来。当向上滚动ListView时,原先位于最上面的list&item的view对象会被回收,然后被用来构造新出现的最下面的list&item。这个构造过程就是由getView()方法完成的,getView()的第二个形参&View&convertView就是被缓存起来的list&item的view对象(初始化时缓存中没有view对象则convertView是null)。
&&&&由此可以看出,如果我们不去使用convertView,而是每次都在getView()中重新实例化一个View对象的话,即浪费时间,也造成内存垃圾,给垃圾回收增加压力,如果垃圾回收来不及的话,虚拟机将不得不给该应用进程分配更多的内存,造成不必要的内存开支。
四、占用内存较多的对象(图片过大)造成内存溢出及其解决方案
因为Bitmap占用的内存实在是太多了,特别是分辨率大的图片,如果要显示多张那问题就更显著了。Android分配给Bitmap的大小只有8M。
方法1:等比例缩小图片
有时候,我们要显示的区域很小,没有必要将整个图片都加载出来,而只需要记载一个缩小过的图片,这时候可以设置一定的采样率,那么就可以大大减小占用的内存。
BitmapFactory.Options
options =&new&BitmapFactory.Options();
options.inSampleSize
尽量不要使用setImageBitmap或setImageResource或BitmapFactory.decodeResource来设置一张大图,
因为这些函数在完成decode后,最终都是通过java层的createBitmap来完成的,需要消耗更多内存。
因此,改用先通过BitmapFactory.decodeStream方法,创建出一个bitmap,再将其设为ImageView的 source,
decodeStream最大的秘密在于其直接调用JNI&&nativeDecodeAsset()来完成decode,
无需再使用java层的createBitmap,从而节省了java层的空间。&
方法2:对图片采用软引用,及时地进行recycle()操作
虽然,系统能够确认Bitmap分配的内存最终会被销毁,但是由于它占用的内存过多,所以很可能会超过java堆的限制。因此,在用完Bitmap时,要及时的recycle掉。recycle并不能确定立即就会将Bitmap释放掉,但是会给虚拟机一个暗示:“该图片可以释放了”。
SoftReference&Bitmap&
&&&&&&&&&&&&&&&bitmap
=&new&SoftReference&Bitmap&(pBitmap);
&&if(bitmap
!=&null){&
&&&&&&&&&&if(bitmap.get()
!=&null&&&
!bitmap.get().isRecycled()){
&&&&&&&&&&&&&&bitmap.get().recycle();
&&&&&&&&&&&&&&bitmap
&&&&&&&&&&}
方法3:&单个页面,横竖屏切换N次后 OOM
1.&看看页面布局当中有没有大的图片,比如背景图之类的。去除xml中相关设置,改在程序中设置背景图(放在onCreate()方法中):
bg = getResources().getDrawable(R.drawable.bg);
&XXX.setBackgroundDrawable(rlAdDetailone_bg);
在Activity destory时注意,bg.setCallback(null);&防止Activity得不到及时的释放。
2.&跟上面方法相似,直接把xml配置文件加载成view&再放到一个容器里,然后直接调用 this.setContentView(View view);避免xml的重复加载。
方法4:在页面切换时尽可能少地重复使用一些代码。比如:重复调用数据库,反复使用某些对象等等.....
方法5:Android堆内存也可以自己定义大小和优化Dalvik虚拟机的内存
--http://blog.csdn.net/wenhaiyan/article/details/5519567
&&&&注意:若使用这种方法:project build target&只能选择 &= 2.2 版本,否则编译将通不过。所以不建议用这种方式。
五、Android中内存泄露监测
内存监测工具&DDMS --& Heap
使用方法比较简单:
·&&&&&&&&选择DDMS视图,并打开Devices视图和Heap视图
·&&&&&&&&点击选择要监控的进程,比如:上图中我选择的是system_process
·&&&&&&&&选中Devices视图界面上的&update heap&&图标
·&&&&&&&&点击Heap视图中的&Cause GC&&按钮(相当于向虚拟机发送了一次GC请求的操作)
在Heap视图中选择想要监控的Type,一般我们会观察dataobject的&total size的变化,正常情况下total size的值会稳定在一个有限的范围内,也就说程序中的代码良好,没有造成程序中的对象不被回收的情况。如果代码中存在没有释放对象引用的情况,那么data object的total size在每次GC之后都不会有明显的回落,随着操作次数的增加而total size也在不断的增加。(说明:选择好data object后,不断的操作应用,这样才可以看出total
size的变化)。如果totalsize确实是在不断增加而没有回落,说明程序中有没有被释放的资源引用。那么我们应该怎么来定位呢?
Android中内存泄露定位
通过DDMS工具可以判断应用程序中是否存在内存泄漏的问题,那又如何定位到具体出现问题的代码片段,最终找到问题所在呢?内存分析工具MAT Memory Analyzer Tool解决了这一难题。MAT工具是一个Eclipse 插件,同时也有单独的RCP 客户端,MAT工具的解析文件是.hprof,这个文件存放了某进程的内存快照。MAT工具定位内存泄漏具体位置的方法如下:
&&&① 生成.hprof文件。Eclipse中生成.hprof文件的方法有很多,不同Android版本中生成.hprof的方式也稍有差别,但它们整体思路是一样的。我们在DDMS界面选中想要分析的应用进程,在Devices视图界面上方的一行图标按钮中,同时选中“Update Heap”和“Dump HPROF file”两个按钮,这时DDMS将会自动生成当前选中进程的.hprof文件。
&&&② 将.hprof 文件导入到MAT工具中,MAT工具会自动解析并生成报告,点击“Dominator Tree”按钮,并按包分组,选择已定义的包类点右键,在弹出的菜单中选择List objects﹥With incoming references,这时会列出所有可疑的类。右键点击某一项,并选择Path to GC Roots﹥excludeweak/soft references,MAT工具会进一步筛选出跟程序相关的所有内存泄漏的类。这样就可以追踪到某一个产生内存泄漏的类的具体代码中。
&&&使用MAT内存分析工具查找内存泄漏的根本思路是找到哪个类的对象的引用没有被释放,然后分析没有被释放的原因,最终定位到代码中哪些片段存在着内存泄漏。
版权所有 爱编程 (C) Copyright 2012. . All Rights Reserved.
闽ICP备号-3
微信扫一扫关注爱编程,每天为您推送一篇经典技术文章。如何定位和解决Andorid的内存溢出问题(大总结)
如何定位和解决Andorid的内存溢出问题(大总结)
转载请备注出自于:http://blog.csdn.net/qq_/article/details/
我们经常在做项目过程中遇到内存溢出的问题,同时面试中关于OOM的问题也常常出现。
这里,我将前辈们解决Andorid内存溢出的方法重新整理一番,方便自己以后使用。
一、Android的内存机制
android应用层是由java开发的,android的davlik虚拟机与jvm也类似,只不过它是基于寄存器的。在java中,通过new为对象分配内存,所有对象在java堆内分配空间;而内存的释放是由垃圾收集器(GC)来回收的。 Java采用了有向图的原理。Java将引用关系考虑为图的有向边,有向边从引用者指向引用对象。线程对象可以作为有向图的起始顶点,该图就是从起始顶点(GC roots)开始的一棵树,根顶点可以到达的对象都是有效对象,GC不会回收这些对象。如果某个对象
(连通子图)与这个根顶点不可达(注意,该图为有向图),那么我们认为这个(这些)对象不再被引用,可以被GC回收。
二、Android的内存溢出原因
1、内存泄露导致
由于我们程序的失误,长期保持某些资源(如Context)的引用,垃圾回收器就无法回收它,当然该对象占用的内存就无法被使用,这就造成内存泄露。
Android&中常见就是Activity被引用在调用finish之后却没有释放,第二次打开activity又重新创建,这样的内存泄露不断的发生,则会导致内存的溢出。
Android的每个应用程序都会使用一个专有的Dalvik虚拟机实例来运行,它是由Zygote服务进程孵化出来的,也就是说每个应用程序都是在属于自己的进程中运行的。Android为不同类型的进程分配了不同的内存使用上限,如果程序在运行过程中出现了内存泄漏的而造成应用进程使用的内存超过了这个上限,则会被系统视为内存泄漏,从而被kill掉,这使得仅仅自己的进程被kill掉,而不会影响其他进程.
2、占用内存较多的对象
保存了多个耗用内存过大的对象(如Bitmap)或加载单个超大的图片,造成内存超出限制。
三、常见的内存泄漏问题及其解决方案
1、引用没释放造成的内存泄露
1.1注册没取消造成的内存泄露
&这种Android的内存泄露比纯Java的内存泄漏还要严重,因为其他一些Android程序可能引用系统的Android程序的对象(比如注册机制)。即使Android程序已经结束了,但是别的应用程序仍然还有对Android程序的某个对象的引用,泄漏的内存依然不能被垃圾回收。
1.2集合中对象没清理造成的内存泄露
我们通常把一些对象的引用加入到了集合中,当我们不需要该对象时,并没有把它的引用从集合中清理掉,这样这个集合就会越来越大。如果这个集合是static的话,那情况就更严重了。
1.3&static
&static是Java中的一个关键字,当用它来修饰成员变量时,那么该变量就属于该类,而不是该类的实例。
&&& private static ActivitymC&&&&&& //省略
如何才能有效的避免这种引用的发生呢?
&&&&第一,应该尽量避免static成员变量引用资源耗费过多的实例,比如Context。
&&&&第二、Context尽量使用ApplicationContext,因为Application的Context的生命周期比较长,引用它不会出现内存泄露的问题。
看使用的周期是否在activity周期内,如果超出,必须用application;常见的情景包括:AsyncTask,Thread,第三方库初始化等等。还有些情景,只能用activity:比如,对话框,各种View,需要startActivity的等。总之,尽可能使用Application。
&&&&第三、使用WeakReference代替强引用。比如可以使用WeakReference&Context&mContextR
1.4、线程(内部类的使用)
线程产生内存泄露的主要原因在于线程生命周期的不可控。如果我们的线程是Activity的内部类,所以MyThread中保存了Activity的一个引用,当MyThread的run函数没有结束时,MyThread是不会被销毁的,因此它所引用的老的Activity也不会被销毁,因此就出现了内存泄露的问题。
如果非静态内部类的方法中,有生命周期大于其所在类的,那就有问题了。比如:AsyncTask、Handler,这两个类都是方便开发者执行异步任务的,但是,这两个都跳出了Activity/Fragment的生命周期。
&&&&第一、将线程的内部类,改为静态内部类。
&&&&&&&原因:
因为非静态内部类会自动持有一个所属类的实例,如果所属类的实例已经结束生命周期,但内部类的方法仍在执行,就会hold其主体(引用)。也就使主体不能被释放,亦即内存泄露。静态类编译后和非内部类是一样的,有自己独立的类名。不会悄悄引用所属类的实例,所以就不容易泄露。
&&&&第二、如果需要引用Acitivity,使用弱引用。
2、资源对象没关闭造成的内存泄露
资源性对象比如(Cursor,File文件等)往往都用了一些缓冲,我们在不使用的时候,应该及时关闭它们,以便它们的缓冲及时回收内存。而不是等待GC来处理。它们的缓冲不仅存在于java虚拟机内,还存在于java虚拟机外。如果我们仅仅是把它的引用设置为null,而不关闭它们,往往会造成内存泄露。因为有些资源性对象,比如SQLiteCursor(在析构函数finalize(),如果我们没有关闭它,它自己会调close()关闭),如果我们没有关闭它,系统在回收它时也会关闭它,但是这样的效率太低了。而且android数据库中对Cursor资源的是又限制个数的,如果不及时close掉,会导致别的地方无法获得。
3、一些不良代码成内存压力
有些代码并不造成内存泄露,但是它们,或是对没使用的内存没进行有效及时的释放,或是没有有效的利用已有的对象而是频繁的申请新内存,对内存的回收和分配造成很大影响的,容易迫使虚拟机不得不给该应用进程分配更多的内存,造成不必要的内存开支。
3.1 Bitmap没调用recycle()
Bitmap对象在不使用时,我们应该先调用recycle()释放内存,然后才设置为null.
虽然recycle()从源码上看,调用它应该能立即释放Bitmap的主要内存,但是测试结果显示它并没能立即释放内存。但是我猜应该还是能大大的加速Bitmap的主要内存的释放。
3.2 构造Adapter时,没有使用缓存的&convertView
&以构造ListView的BaseAdapter为例,在BaseAdapter中提共了方法:
public&View&getView(int&position,&View&convertView,&ViewGroup&parent)
来向ListView提供每一个item所需要的view对象。初始时ListView会从BaseAdapter中根据当前的屏幕布局实例化一定数量的view对象,同时ListView会将这些view对象缓存起来。当向上滚动ListView时,原先位于最上面的list&item的view对象会被回收,然后被用来构造新出现的最下面的list&item。这个构造过程就是由getView()方法完成的,getView()的第二个形参&View&convertView就是被缓存起来的list&item的view对象(初始化时缓存中没有view对象则convertView是null)。
&&&&由此可以看出,如果我们不去使用convertView,而是每次都在getView()中重新实例化一个View对象的话,即浪费时间,也造成内存垃圾,给垃圾回收增加压力,如果垃圾回收来不及的话,虚拟机将不得不给该应用进程分配更多的内存,造成不必要的内存开支。
四、占用内存较多的对象(图片过大)造成内存溢出及其解决方案
因为Bitmap占用的内存实在是太多了,特别是分辨率大的图片,如果要显示多张那问题就更显著了。Android分配给Bitmap的大小只有8M。
方法1:等比例缩小图片
有时候,我们要显示的区域很小,没有必要将整个图片都加载出来,而只需要记载一个缩小过的图片,这时候可以设置一定的采样率,那么就可以大大减小占用的内存。
BitmapFactory.Options
options =&new&BitmapFactory.Options();
options.inSampleSize
尽量不要使用setImageBitmap或setImageResource或BitmapFactory.decodeResource来设置一张大图,
因为这些函数在完成decode后,最终都是通过java层的createBitmap来完成的,需要消耗更多内存。
因此,改用先通过BitmapFactory.decodeStream方法,创建出一个bitmap,再将其设为ImageView的 source,
decodeStream最大的秘密在于其直接调用JNI&&nativeDecodeAsset()来完成decode,
无需再使用java层的createBitmap,从而节省了java层的空间。&
方法2:对图片采用软引用,及时地进行recycle()操作
虽然,系统能够确认Bitmap分配的内存最终会被销毁,但是由于它占用的内存过多,所以很可能会超过java堆的限制。因此,在用完Bitmap时,要及时的recycle掉。recycle并不能确定立即就会将Bitmap释放掉,但是会给虚拟机一个暗示:“该图片可以释放了”。
SoftReference&Bitmap&
&&&&&&&&&&&&&&&bitmap
=&new&SoftReference&Bitmap&(pBitmap);
&&if(bitmap
!=&null){&
&&&&&&&&&&if(bitmap.get()
!=&null&&&
!bitmap.get().isRecycled()){
&&&&&&&&&&&&&&bitmap.get().recycle();
&&&&&&&&&&&&&&bitmap
&&&&&&&&&&}
方法3:&单个页面,横竖屏切换N次后 OOM
1.&看看页面布局当中有没有大的图片,比如背景图之类的。去除xml中相关设置,改在程序中设置背景图(放在onCreate()方法中):
bg = getResources().getDrawable(R.drawable.bg);
&XXX.setBackgroundDrawable(rlAdDetailone_bg);
在Activity destory时注意,bg.setCallback(null);&防止Activity得不到及时的释放。
2.&跟上面方法相似,直接把xml配置文件加载成view&再放到一个容器里,然后直接调用 this.setContentView(View view);避免xml的重复加载。
方法4:在页面切换时尽可能少地重复使用一些代码。比如:重复调用数据库,反复使用某些对象等等.....
方法5:Android堆内存也可以自己定义大小和优化Dalvik虚拟机的内存
--http://blog.csdn.net/wenhaiyan/article/details/5519567
&&&&注意:若使用这种方法:project build target&只能选择 &= 2.2 版本,否则编译将通不过。所以不建议用这种方式。
五、Android中内存泄露监测
内存监测工具&DDMS --& Heap
使用方法比较简单:
·&&&&&&&&选择DDMS视图,并打开Devices视图和Heap视图
·&&&&&&&&点击选择要监控的进程,比如:上图中我选择的是system_process
·&&&&&&&&选中Devices视图界面上的&update heap&&图标
·&&&&&&&&点击Heap视图中的&Cause GC&&按钮(相当于向虚拟机发送了一次GC请求的操作)
在Heap视图中选择想要监控的Type,一般我们会观察dataobject的&total size的变化,正常情况下total size的值会稳定在一个有限的范围内,也就说程序中的代码良好,没有造成程序中的对象不被回收的情况。如果代码中存在没有释放对象引用的情况,那么data object的total size在每次GC之后都不会有明显的回落,随着操作次数的增加而total size也在不断的增加。(说明:选择好data object后,不断的操作应用,这样才可以看出total
size的变化)。如果totalsize确实是在不断增加而没有回落,说明程序中有没有被释放的资源引用。那么我们应该怎么来定位呢?
Android中内存泄露定位
通过DDMS工具可以判断应用程序中是否存在内存泄漏的问题,那又如何定位到具体出现问题的代码片段,最终找到问题所在呢?内存分析工具MAT Memory Analyzer Tool解决了这一难题。MAT工具是一个Eclipse 插件,同时也有单独的RCP 客户端,MAT工具的解析文件是.hprof,这个文件存放了某进程的内存快照。MAT工具定位内存泄漏具体位置的方法如下:
&&&① 生成.hprof文件。Eclipse中生成.hprof文件的方法有很多,不同Android版本中生成.hprof的方式也稍有差别,但它们整体思路是一样的。我们在DDMS界面选中想要分析的应用进程,在Devices视图界面上方的一行图标按钮中,同时选中“Update Heap”和“Dump HPROF file”两个按钮,这时DDMS将会自动生成当前选中进程的.hprof文件。
&&&② 将.hprof 文件导入到MAT工具中,MAT工具会自动解析并生成报告,点击“Dominator Tree”按钮,并按包分组,选择已定义的包类点右键,在弹出的菜单中选择List objects﹥With incoming references,这时会列出所有可疑的类。右键点击某一项,并选择Path to GC Roots﹥excludeweak/soft references,MAT工具会进一步筛选出跟程序相关的所有内存泄漏的类。这样就可以追踪到某一个产生内存泄漏的类的具体代码中。
&&&使用MAT内存分析工具查找内存泄漏的根本思路是找到哪个类的对象的引用没有被释放,然后分析没有被释放的原因,最终定位到代码中哪些片段存在着内存泄漏。
我的热门文章
即使是一小步也想与你分享

我要回帖

更多关于 如何解决java内存溢出 的文章

 

随机推荐