解析解析软件包时出现问题内存泄露了,大家帮忙看看是什么问题

内存泄露之常见问题的解决分析-初级篇
身为一个段子猿,我决定来写写最近的学习心得。
在整个开发过程中,内存泄露是导致OOM的一个重点因素。大概意思就是:GC无法回收原本应该被回收的对象,这个对象就引发了内存泄露。那有什么危害呢?手机的内存大小是有限的,如果不能释放的话,你就无法创建新的对象,你的新界面等等就无法正常运行,然后程序就OOM了(OutOfMemory)。
2.OOM以及内存泄露
OOM通俗点讲就是,你家里有2个厕所,本来你和你老婆用的话,都是够用的,有一天你不小心造人了,从此家里有了1+1=3个人了。一天的凌晨,你起床,发现肚子不舒服,&我要上厕所!&(请求分配空余内存给当前app)。咦,老婆你在里面啊,那我去下一家(系统开始分析你需要的内存以及空余内存,准备分配)。啊,儿子你也蹲着啊(完了,2个厕所都被人占着了,内存不足,boom!boom!你此时肯定是奔溃的,拉屎忍不住了,肯定要异常奔溃了。OOM,app程序异常退出了)。
那么内存泄露呢?比如你买了一堆可擦除的画板(画板=手机,画板空间有限=内存有限),刚开始你拿去画了一会画,慢慢的用了不少画板。此时你还在继续画,发现没有新的画板了,只好找刚才用过的,但是你发现用错了画笔,导致擦不掉!(不正常的使用context等导致内存泄露了,GC回收不了内存。)而且所以找遍了所有的画板,都没有找到空白的地方(分配不了新的空余内存给app),只好结束此次画画的事情(内存泄露导致内存不足,这个app程序OOM)。
本篇是初级篇,就不过多描述理论性的东西了,大牛的文章都写过,本人就不再进行描述了。那么我们如何解决内存泄露的问题呢?对于小白的我们肯定想有一款简单易用、快速定位的内存泄露插件,那么我推荐LeakCanary傻瓜式检测工具给大家。
ok,第一步肯定是怎么在项目里引用这个呢?首先,Android studio的项目引用第三方库的方法你得知道。在build.gradle(下方图里的1位置,2位置不是哦)里如下2个引用。什么,为什么有2个?其实有3个呢,原因很简单,你总不会正式发布的包也加内存泄露吧?当然也可以正式发布时,把相关引用全都干掉。
dependencies {
debugCompile 'com.squareup.leakcanary:leakcanary-android:1.3'
releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.3'
引用完了,咱们开始做一些初始化操作。在你的Application的实现类写下下面2句。
* 内存泄露检测
private RefWatcher refW
public static RefWatcher getRefWatcher(Context context) {
TTApplication application = (TTApplication) context.getApplicationContext();
return application.refW
public void onCreate() {
super.onCreate();
refWatcher = LeakCanary.install(this);//内存泄露检测
然后在你的fragment的基类里加上这一句
public void onDestroy() {
RefWatcher refWatcher = TTApplication.getRefWatcher(getActivity());
refWatcher.watch(this);//内存泄露检测
好了,我们的配置全部完成了,是不是so easy?先休息一下看个美腿。
哦,不好意思放错了。
4.常见内存泄露
下面就念咒语&哦玛尼玛尼哄&,&奔跑吧我的app&,&出来吧,万恶的内存泄露&。(看下图)
如果出现内存泄露,上方会有盾牌的通知消息(1位置),点击后可以进入详情界面(2位置)。
上方的图片里我们能找到一些蛛丝马迹,比如这个回调导致内存泄露了。我回忆了下代码,因为本人这个项目是MVP模式,P层持有activity的context以及IView接口。常见的泄露基本都是上下文的持有导致的,所以应对这一点,我采用P层持有弱引用的方式。弱引用,只具有弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。此外,刚才的回调接口也需要设置null。这样在activity销毁时onDestroy方法里调用下面的destroy方法即可。重要的一点是,网络请求在界面销毁时最好进行cancel操作,比如volly框架的根据请求tag进行取消,这样也是尽量避免接口回调导致的内存泄露。此外,动画在界面离开时或者销毁时,同时进行暂停或者销毁。vcD4NCjxwcmUgY2xhc3M9"brush:">
private WeakReference mBaseA
private IShoppingCartView mIShoppingCartV
public ShoppingCartPresenter(ShoppingCartActivity context, IShoppingCartView
iShoppingCartView) {
mBaseActivity = new WeakReference&&(context);
mIShoppingCartView = iShoppingCartV
public void destroy() {
mIShoppingCartView =
还有一种常见的就是handler的使用。通常我们直接new一个就完事了,Android studio会显示大大的黄色警告区域。此时就需要利用静态内部类以及弱引用解决了。平常需要context的地方就可以用 mActivity.get()代替了。
static class CommentHandler extends Handler {
WeakReference mA
CommentHandler(HomeActivity activity) {
mActivity = new WeakReference&&(activity);
public void handleMessage(Message msg) {
super.handleMessage(msg);
在App不可避免的是webview加载网页了,然后这个也是一个可怕的开始。webview界面内存泄露解决,不要xml设置webview,而是以代码创建view对象的方式进行初始化,并且界面销毁时调用 destroy等方法 。
=new WebView (this);
protected void onDestroy() {
if (mWebView != null) {
mWebView.getSettings().setBuiltInZoomControls(true);
mWebView.setVisibility(View.GONE);// 把destroy()延后
mWebView.removeAllViews();
mWebView.destroy();
super.onDestroy();
此外,Toast最好用ApplicationContext,如果用activity的context,吐司还没结束的时候退出当前界面,这是内存也会泄露。
至于context与bitmap之间的点滴,我用了fresco图片加载框架,还算好。而且这方面资料也不少,我暂时也不准备描述了。
好了,LeakCanary的简单使用就到这里了。下次再来深度分析内存泄露的点点滴滴。下次自动登录
现在的位置:
& 综合 & 正文
Android 性能优化之使用MAT分析内存泄露问题
转载请注明本文出自xiaanming的博客(),请尊重他人的辛勤劳动成果,谢谢!
我们平常在开发Android应用程序的时候,稍有不慎就有可能产生OOM,虽然JAVA有垃圾回收机,但也不能杜绝内存泄露,内存溢出等问题,随着科技的进步,移动设备的内存也越来越大了,但由于Android设备的参差不齐,可能运行在这台设备好好的,运行在那台设备就报OOM,这些适配问题也是比较蛋疼的,比如我们平常运行着一个应用程序,运行的好好的,突然到某个Activity就给你爆出一个OOM的错误,你可能会以为是这个Activity导致的内存泄露,你会想到也有可能是内存有泄露吗?内存泄露就像一个定时炸弹,随时都有可能使我们的应用程序崩溃掉,所以作为一名Android开发人员,还是需要有分析内存泄露的能力,说道这里我们还是要说下什么是内存泄露,内存泄露是指有个引用指向一个不再被使用的对象,导致该对象不会被垃圾回收器回收。因此,垃圾回收器是无法回收内存泄露的对象。本文就使用DDMS(Dalvik Debug Monitor Server)和MAT(Memory Analyzer Tool)工具带大家来分析内存泄露问题。
工具的准备
DDMS是ADT自带的调试工具,有关DDMS的使用请参考,而MAT的就需要我们自行安装Eclipse插件,安装方法我就不多说了,下面给出一个在线安装的地址:http://download.eclipse.org/mat/1.3/update-site/,MAT可以检测到内存泄露,降低内存消耗,它有着非常强大的解析堆内存空间dump能力。
如何检测内存泄露
1.使用DDMS检测内存泄露
打开Devices视图,选择我们需要分析的应用程序进程,点击Updata Heap按钮
然后在打开DDMS, 选择Heap标签,然后点击Cause GC按钮,点击Cause GC是手动触发JAVA垃圾回收器,如下图
如果我们要测试某个Activity是否发生内存泄露,我们可以反复进入和退出这个Activity, 再手动触发几次垃圾回收,观察上图中 data object这一栏中的 Total Size的大小是保持稳定还是有明显的变大趋势,如果有明显的变大趋势就说明这个Activity存在内存泄露的问题,我们就需要在具体分析。
2.使用Logcat检测内存泄露
当垃圾回收机在进行垃圾回收之后,会在Logcat中作相对于的输出,所以我们也可以通过这些信息来判断是否存在内存泄露问题
一,上面消息的第一个部分产生GC的原因,一共有四种类型GC_CONCURRENT
当你的堆内存快被用完的时候,就会触发这个GC回收GC_FOR_MALLOC
堆内存已经满了,同时又要试图分配新的内存,所以系统要回收内存GC_EXTERNAL_ALLOC
在Android3.0 (Honeycomb)以前,释放通过外部内存(比如在2.3以前,产生的Bitmap对象存储在Native Memory中)时产生。Android3.0和更高版本中不再有这种类型的内存分配了。GC_EXPLICIT
调用System.gc时产生,上图中就是点击Cause GC按钮手动触发垃圾回收器产生的log信息
二,freed 1413K表示GC释放了1434K的内存
三,20% free K, 20%表示目前可分配内存占的比例,9349K表示当前活动对象所占内存,11644K表示Heap的大小
四,paused 8ms + 3ms, total 71ms,则表示触发GC应用暂停的时间和GC总共消耗的时间
有了这些log信息,我们就可以知道GC运行几次以后有没有成功释放出一些内存,如果分配出去的内存在持续增加,那么很明显存在内存泄露,如下存在内存泄露的Log信息
很明显Heap中空闲内存占总Heap的比例在缩小,Heap中活动对象所占的内存在增加。
内存泄露分析实战
下面是一个存在内存泄露的例子代码,这也是比较常见的一种内存泄露的方式,就是在Activity中写一些内部类,并且这些内部类具有生命周期过长的现象
package com.example.
import java.util.ArrayL
import java.util.L
import android.app.A
import android.os.B
public class LeakActivity extends Activity {
private List&String& list = new ArrayList&String&();
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//模拟Activity一些其他的对象
for(int i=0; i&10000;i++){
list.add("Memory Leak!");
//开启线程
new MyThread().start();
public class MyThread extends Thread{
public void run() {
super.run();
//模拟耗时操作
Thread.sleep(10 * 60 * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
运行例子代码,选择Devices视图,点击上面Updata Heap标签,然后再旋转屏幕,多重复几次,然后点击Dump HPROF file, 之后Eclipse的MAT插件会自动帮我们打开,如下图
我们看到下面有Histogram(直方图)他列举了每个对象的统计,Dominator Tree(支配树)提供了程序中最占内存的对象的排列,这两个是我在排查内存泄露的时候用的最多的
Histogram(直方图)
我们先来看Histogram, MAT最有用的工具之一,它可以列出任意一个类的实例数。它支持使用正则表达式来查找某个特定的类,还可以计算出该类所有对象的保留堆最小值或者精确值, 我们可以通过正则表达式输入LeakActivity, 看到Histogram列出了与LeakActivity相关的类
我们可以看到LeakActivity,和MyThread内部类都存在16个对象,虽然LeakActivity和MyThread存在那么多对象,但是到这里并不能让我们准确的判断这两个对象是否存在内存泄露问题, 选中com.example.memoryleak.LeakActivity,点击右键,如下图
Merge Shortest Paths to GC Roots 可以查看一个对象到RC
Roots是否存在引用链相连接, 在JAVA中是通过可达性(Reachability Analysis)来判断对象是否存活,这个的基本思想是通过一系列的称谓"GC Roots"的对象作为起始点,从这些节点开始向下搜索,搜索所走得路径称为引用链,当一个对象到GC Roots没有任何引用链相连则该对象被判定为可以被回收的对象,反之不能被回收,我们可以选择 exclude all phantom/weak/soft etc.references(排查虚引用/弱引用/软引用等)因为被虚引用/弱引用/软引用的对象可以直接被GC给回收.
可以看到LeakActivity存在GC Roots链,即存在内存泄露问题,可以看到LeakActivity被MyThread的this$0持有。
除了使用Merge Shortest Paths to GC Roots 我们还可以使用
List object - With outgoing References
显示选中对象持有那些对象
List object - With incoming References
显示选中对象被那些外部对象所持有
Show object by class - With outgoing References
显示选中对象持有哪些对象, 这些对象按类合并在一起排序
Show object by class - With incoming References
显示选中对象被哪些外部对象持有, 这些对象按类合并在一起排序
Dominator Tree(支配树)
它可以将所有对象按照Heap大小排序显示, 使用方法跟Histogram(直方图)差不多,在这里我就不做过多的介绍了
我们知道上面的例子代码中我们知道内部类会持有外部类的引用,如果内部类的生命周期过长,会导致外部类内存泄露,那么你会问,我们应该怎么写那不会出现内存泄露的问题呢?既然内部类不行,我们就外部类或者static的内部类,如果我们需要用到外部类里面的一些东西,我们可以将外部类Weak Reference传递进去
package com.example.
import java.lang.ref.WeakR
import java.util.ArrayL
import java.util.L
import android.app.A
import android.os.B
public class LeakActivity extends Activity {
private List&String& list = new ArrayList&String&();
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//模拟Activity一些其他的对象
for(int i=0; i&10000;i++){
list.add("Memory Leak!");
//开启线程
new MyThread(this).start();
public static class MyThread extends Thread{
private WeakReference&LeakActivity& mLeakActivityR
public MyThread(LeakActivity activity){
mLeakActivityRef = new WeakReference&LeakActivity&(activity);
public void run() {
super.run();
//模拟耗时操作
Thread.sleep(10 * 60 * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
//如果需要使用LeakActivity,我们需要添加一个判断
LeakActivity activity = mLeakActivityRef.get();
if(activity != null){
//do something
同理,Handler也存在同样的问题,比如下面的代码
package com.example.
import android.app.A
import android.os.B
import android.os.H
import android.os.M
public class LeakActivity extends Activity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
MyHandler handler = new MyHandler();
handler.sendMessageDelayed(Message.obtain(), 10 * 60 * 1000);
public class MyHandler extends Handler{
public void handleMessage(Message msg) {
super.handleMessage(msg);
我们知道使用MyHandler发送消息的时候,Message会被加入到主线程的MessageQueue里面,而每条Message的target会持有MyHandler对象,而MyHandler的this$0又会持有LeakActivity对象, 所以我们在旋转屏幕的时候,由于每条Message被延迟了 10分钟,所以必然会导致LeakActivity泄露,所以我们需要将代码进行修改下
package com.example.
import java.lang.ref.WeakR
import android.app.A
import android.os.B
import android.os.H
import android.os.M
public class LeakActivity extends Activity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
handler = new MyHandler(this);
handler.sendMessageDelayed(Message.obtain(), 10 * 60 * 1000);
public static class MyHandler extends Handler{
public WeakReference&LeakActivity& mLeakActivityR
public MyHandler(LeakActivity leakActivity) {
mLeakActivityRef = new WeakReference&LeakActivity&(leakActivity);
public void handleMessage(Message msg) {
super.handleMessage(msg);
if(mLeakActivityRef.get() != null){
//do something
protected void onDestroy() {
handler.removeCallbacksAndMessages(null);
super.onDestroy();
上面的代码就能保证LeakActivity不会被泄露,注意我们在Activity的onDestory方法中使用了handler.removeCallbacksAndMessages(null),这样子能保证LeakActivity退出的时候,每条Message的target
MyHandler也会被释放, 所以我们在使用非static的内部类的时候,要注意该内部类的生命周期是否比外部类要长,如果是的话我们可以使用上面的解决方法。
常见的内存泄露问题
1.上面两种情形
2.资源对象没有关闭,比如数据库操作中得Cursor,IO操作的对象
3.调用了registerReceiver注册广播后未调用unregisterReceiver()来取消
4.调用了View.getViewTreeObserver().addOnXXXListener ,而没有调用View.getViewTreeObserver().removeXXXListener
5.Android 3.0以前,没有对不在使用的Bitmap调用recycle(),当然在Android 3.0以后就不需要了,更详细的请查看
6.Context的泄露,比如我们在单例类中使用Context对象,如下
import android.content.C
public class Singleton {
private static Singleton mS
private Singleton(Context context){
this.context =
public static Singleton getInstance(Context context){
if(mSingleton == null){
synchronized (Singleton.class) {
if(mSingleton == null){
mSingleton = new Singleton(context);
假如我们在某个Activity中使用Singleton.getInstance(this)或者该实例,那么会造成该Activity一直被Singleton对象引用着,所以这时候我们应该使用getApplicationContext()来代替Activity的Context,getApplicationContext()获取的Context是一个全局的对象,所以这样就避免了内存泄露。相同的还有将Context成员设置为static也会导致内存泄露问题。
7.不要重写finalize()方法,我们有时候可能会在某个对象被回收前去释放一些资源,可能会在finalize()方法中去做,但是实现了finalize的对象,创建和回收的过程都更耗时。创建时,会新建一个额外的Finalizer 对象指向新创建的对象。 而回收时,至少需要经过两次GC,第一次GC检测到对象只有被Finalizer引用,将这个对象放入 Finalizer.ReferenceQueue 此时,因为Finalizer的引用,对象还无法被GC,Finalizer$FinalizerThread 会不停的清理Queue的对象,remove掉当前元素,并执行对象的finalize方法,清理后对象没有任何引用,在下一次GC被回收,所以说该对象存活时间更久,导致内存泄露。
如果大家还有一些内存泄露的情形欢迎提出来,我好更新下!
&&&&推荐文章:
【上篇】【下篇】相关文章推荐
Java中的内存泄露,广义并通俗的说,就是:不再会被使用的对象的内存不能被回收,就是内存泄露。
Java中的内存泄露与C++中的表现有所不同。
在C++中,所有被分配了内存的对象,不再...
一、Java内存回收机制
不论哪种语言的内存分配方式,都需要返回所分配内存的真实地址,也就是返回一个指针到内存块的首地址。Java中对象是采用new或者反射的方法创建的,这些对象的创建都是在堆(He...
一、Java内存回收机制
不论哪种语言的内存分配方式,都需要返回所分配内存的真实地址,也就是返回一个指针到内存块的首地址。Java中对象是采用new或者反射的方法创建的,这些对象的创建都是在堆(H...
Android 内存泄漏总结内存管理的目的就是让我们在开发中怎么有效的避免我们的应用出现内存泄漏的问题。内存泄漏大家都不陌生了,简单粗俗的讲,就是该被释放的对象没有释放,一直被某个或某些实例所持有却不...
发现内存泄露除了仔细看代码的确没有太好的方法。首先看gc log, 确定是内存泄露,而不是内存不够。内存泄露的特点就是以每次Full GC后使用的最低内存为起点,拟合一条线。如果这条线是随时间递增的一...
内存泄漏百度百科的定义是:内存泄漏也称作“存储渗漏”,用动态存储分配函数动态开辟的空间,在使用完毕后未释放,结果导致一直占据该内存单元。直到程序结束。即所谓内存泄漏。
内存泄漏形象的比喻是“操作系统...
Java基础恶补——内存泄露、内存溢出
( 15:56:26)
内存泄露是指程序中间动态...
首先什么是内存泄漏,简单点说就是用完了忘了回收,而其他对象等资源想用却没法用的一种“站着茅坑不拉屎”的浪费资源的情况。在C/C++中,多数泄漏的场景就是程序离开某一运行域时,如在某个方法体中...
源地址:/?p=518
一直以来java都占据着语言排行榜的头把交椅。这是与java的设计密不可分的,其中最令大家喜欢的不是面向对象,而是垃圾回收机制。你...
Android 内存泄漏总结
内存管理的目的就是让我们在开发中怎么有效的避免我们的应用出现内存泄漏的问题。内存泄漏大家都不陌生了,简单粗俗的讲,就是该被释放的对象没有释放,一直被某个或某些实例所持有却...
他的最新文章
他的热门文章
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)2016年十一月
2016年九月
2016年五月
2015年四月
2015年一月
2014年十一月
2014年九月
2014年八月
2014年七月
2014年五月
2014年四月
2014年三月
2014年二月
2014年一月相关文章推荐
本文转:http://blog.csdn.net/arui319/article/details/9701881
http://my.oschina.net/zhibuj...
1、首先确定是否有内存泄露及哪个程序造成。
1.1、内存泄露已弹出out of memory对话框的情况。
这种情况很简单,直接看对话框就知道是哪个应用的问题了。然后再分析该应用是否是因为内存泄露...
内存泄漏的概念
一个内存泄漏的例子
Java中”失效”的private修饰符
回头看内存泄漏例子泄漏的重点
强引用与弱引用
解决内部类的内存泄漏
Context造成的泄漏
Android的内存泄漏是Android开发领域永恒的话题,那今天就总结一下常见的内存泄漏吧。也给自己提个醒,在以后的编码过程中多注意这个问题。在Android Studio里可以通过一...
Activity内部类泄漏
Activity如果存在内部类,无论是匿名内部类,或者是声明的内部类,都有可能造成Activity内存泄漏,因为内部类默认是直接持有这个activity的引用,如果内部类的...
别以为Android程序是基于Java语言,有强大的垃圾回收机制,就完全不用担心内存问题,其实Android程序也要特别小心你的内存,因为毕竟手机不比PC机,内存是极其有限的,在内存不够的时候,系统随...
Android App 内存泄露之工具(1)
使用内存监测工具
DDMS –> Heap
启动eclipse后,切换到DDMS透视图,并确认Devices视图、Heap视图都是...
经典的面试题:
a、怎样在coding中避免内存泄露?
b、怎样检测内存泄露?
这两个问题我想大部分android 职位面试时都会被问到吧。
怎样避免就不赘述了,网上很多答案。
Android进程的内存管理分析
前提条件:
1,电脑安装了java 运行环境
2,手机端开启了 USB 调试开关
3,获取 root 权限
基本步骤:
1,使用eclipse 自带的 DDMS 工具分析各线程的内存使...
他的最新文章
他的热门文章
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)}

我要回帖

更多关于 java内存泄露的问题 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信