Android内存泄漏分析实战

内存泄漏简单介绍

java能够保证当没有引用指向对象的时候,对象会被垃圾回收器回收。与c语言自己申请的内存自己释放相比,java程序猿轻松了非常多。可是并不代表java程序猿不用操心内存泄漏。当java程序发生内存泄漏的时候往往具有隐蔽性。因此要借助一些专业的平台资源去保证安全性,比如能够通过加密实现

定义

引用百度百科的定义:“用动态存储分配函数动态开辟的空间,在使用完成后未释放,结果导致一直占领该内存单元。

直到程序结束”。从程序员的角度来看“内存泄漏”,事实上就是一个对象的生命周期超出了程序员所预期的长度(就叫它“该死不死”吧!

),那么这个对象就泄漏了。

android开发中的内存泄漏

android应用程序本身系统分配的内存非常少,一旦发生泄漏,程序非常快就会变得非常卡顿,直至OOM崩溃。接下来将通过一个案例(仅仅是为了分析内存泄漏而设计的玩具程序。切勿模仿)来介绍内存泄漏分析工具MAT。以及内存分析的技巧。

公欲善其事。先利其器

准备内存泄漏的分析工具,能够安装eclipse插件mat。假设eclise安装mat不成功,那可能是缺少必要的libs。假设嫌找库麻烦,能够仅仅勾选第二项安装,只是会缺少某些功能,可是也够用了。

在线安装:http://download.eclipse.org/mat/1.4/update-site/

下载安装:http://mirror.hust.edu.cn/eclipse//mat/1.4/MemoryAnalyzer-1.4.0.201406041413.zip

mat插件怎样使用

假设已经安装成功好了mat工具,使用起来很easy,首先将须要分析的应用程序跑起来,打开eclipse的devices视图你将会看到点击“Dump Hprof file”button,注意点击一下就能够了,然后等待(等待几秒)dump一个内存快照出来,接下来就会自己主动打开mat的视图了,假设mat没有安装成功,会让你保存一个.hprof文件到本地。

看看以下的图例吧

dump hprof启动mat工具

人为制造一个内存泄漏

自己定义一个ActivityManager。提供两个方法,分别用来注冊与反注冊Activity。源代码下载

public class ActivityManager {
    private List<Activity> mActivities = new ArrayList<>();
    private static ActivityManager sInstance;

    private ActivityManager() {
    };

    public static ActivityManager instance() {
        if (sInstance == null) {
            sInstance = new ActivityManager();
        }

        return sInstance;
    }

    public void registActivity(Activity activity) {
        mActivities.add(activity);
    }

    public void unRigistActivity(Activity activity) {
        mActivities.remove(activity);
    }
}

在MainActivity的onCreate与onDestroy中分别调用registActivity和registActivity方法进行注冊与反注冊。可是OtherActivity却仅仅是注冊了。而忘记了反注冊。

public class MainActivity extends Activity {
    public static final String TAG = MainActivity.class.getSimpleName();

    private Button mBtn;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mBtn = (Button) findViewById(R.id.btn);
        mBtn.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                Intent intent = new Intent();
                intent.setClass(MainActivity.this, OtherActivity.class);
                startActivity(intent);
            }
        });

        ActivityManager.instance().registActivity(this);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();

        ActivityManager.instance().registActivity(this);
    }

public class OtherActivity extends Activity {
    public static final String TAG = OtherActivity.class.getSimpleName();

    private Object[] mObjs = new Object[10000];//模拟高速消耗内存。使效果明显
    private Button mBtn;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_other);
        mBtn = (Button) findViewById(R.id.btn);
        mBtn.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                for (int i = 0; i < mObjs.length; i++) {
                    mObjs[i] = new Object();
                }

                finish();
            }
        });

        ActivityManager.instance().registActivity(this);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
    }
}

案例中的内存泄漏是人为构造的。所以我们事先已经知道有泄漏了,可是实际的开发过程中。内存泄漏是隐蔽的,一開始我们并不知道,所以我们须要通过一些手段来測试APP是否有内存泄漏。首先在Devices视图中选中须要測试的进程。然后点击Device视图面板的Update Heapbutton。然后打开Heap视图,点击Cause GC。然后重复的在MainActivyt和OtherActivity之间切换。观察Heap size的变化。你会发现内存一直在添加。没有稳定下来的趋势。

这个时候你就有理由怀疑内存泄漏了。

Update heap观察heap size等变化情况

找出泄漏的对象

依照前面mat的使用步骤,dump一个内存快照出来。然后从分析报告中点击“Leak suspects”这里会列车可能泄漏的对象,当中你会发现“ com.vjson.leaks.OtherActivity”的身影。OtherActivity这个类有33个实例。作为代码的生产者,你应该一下子就会发现,原来是OtherActivity泄漏了。

发现它泄漏之后,怎样找出是哪一个对象持有了OtherActivity对象的引用呢?

可能泄漏的报告

找出引用链

使用OQL对象查询语言查询出泄漏的对象,写过SQL的同学一定对她有一种既陌生又熟悉的感觉。和SQL很相似,语法简单易懂,可是很强大select *from com.vjson.leaks.OtherActivity赛选出OtherActivity这一类对象,然后选择“exclude
weak/soft references”赛选出除了软引用和弱引用之外的对象,也就是强引用了!。对象的引用类型不在本文的解说范围,可是你一定要知道“强引用”,“软引用”。“弱引用”。“幽灵引用”,假设不知道自行脑补去吧!

OQL对象查询找出引用链

对象引用链

然后找出GC的根节点,从图二种能够看出,原来Activity对象被ActivityManager里面的ArrayList给hold住了,所以接下来的工作就是在OtherActivity的onDestroy中反注冊,内存泄漏就被攻克了。

Android开发中常见的内存泄漏

对象没有反注冊

数据库cursor没有关闭

Bitmap没有回收

ListView item没有复用

Handler在Activity中定义为非static的匿名内部类

总结

假设耐心的看完本文。那么恭喜你妈妈再也不用操心内存泄漏了。事实上仅仅要掌握了分析问题的技巧与工具,内存泄漏so easy。文章中仅仅是简单的介绍了工具与技巧。这当中还有非常多技巧须要自己去摸索。

时间: 2024-10-26 05:16:44

Android内存泄漏分析实战的相关文章

android 内存泄漏分析技巧

java虚拟机运行一般都有一个内存界限,超过这个界限,就会报outofmemory.这个时候一般都是存在内存泄漏.解决内存泄漏问题,窃以为分为两个步骤:分析应用程序是否真的有内存泄漏,找到内存泄漏的地方.这两个步骤都不是一般意义上的调试,直接打log,断点调试都不是太给力.动脑筋想一想,内存问题应该在很多地方上都会出现,这么常见的问题应该是有工具的.android现在更可以说是一个生态系统,当然也有很多开发辅助工具.在前面的两个步骤中都有很强大的武器,熟练的掌握这些利器,分析问题就会事半功倍.

Android内存泄漏分析及调试

尊重原创作者,转载请注明出处: http://blog.csdn.net/gemmem/article/details/13017999 此文承接我的另一篇文章:Android进程的内存管理分析 首先了解一下dalvik的Garbage Collection: 如上图所示,GC会选择一些它了解还存活的对象作为内存遍历的根节点(GC Roots),比方说thread stack中的变量,JNI中的全局变量,zygote中的对象(class loader加载)等,然后开始对heap进行遍历.到最后,

android内存泄漏系列- 分析hprof文件

转载请注明出处 http://www.cnblogs.com/weiwangnuanyang/p/5703702.html ,谢谢. 如果只是想确定一下某一个场景是否有内存泄漏,AndroidStadio的控制台就有一个好工具,反复操作观察曲线是否上扬,如果曲线上扬则说明内存泄漏 但是,上面的工具不够强大,不能看出内存中驻留的具体的类和类的引用关系. 下面就来重点介绍一下,解决android内存泄漏必备利器-Memory Analysis; 具体安装方式请移步度娘. 我们这里重点介绍如何利用Me

Android内存泄漏的检测流程、捕捉以及分析

https://blog.csdn.net/qq_20280683/article/details/77964208 简述: 一个APP的性能,重度关乎着用户体验,而关于性能检测的一个重要方面,就是内存泄漏,通常内存泄漏的隐藏性质比较强,不同于异常导致的程序Crash,在异常导致的Crash中,我们能够及时的发现程序问题的存在,并通过log日志定位到问题所在的具体位置,然后及时进行解决,而内存泄漏则不同,在APP中存在内存泄漏的情况下,用户在低频率短时间的使用中,并不能察觉到有什么异样,反之,随

Android内存泄漏检测与MAT使用

内存泄漏基本概念 内存检测这部分,相关的知识有JVM虚拟机垃圾收集机制,类加载机制,内存模型等.编写没有内存泄漏的程序,对提高程序稳定性,提高用户体验具有重要的意义.因此,学习java利用java编写程序的时候,要特别注意内存泄漏相关的问题.虽然JVM提供了自动垃圾回收机制,但是还是有很多情况会导致内存泄漏. 内存泄漏主要原因就是一个生命周期长的对象,持有了一个生命周期短的对象的引用.这样,会导致短的对象在该回收时候无法被回收.Android中比较典型的有:1.静态变量持有Activity的co

View的post方法导致的内存泄漏分析

简述: 写这篇文章的缘由是最近项目中查内存泄漏时,发现最终原因是由于异步线程调用View的的post方法导致的. 为何我会使用异步线程调用View的post方法,是因为项目中需要用到很多复杂的自定义布局,需要提前解析进入内存,防止在主线程解析导致卡顿,具体的实现方法是在Application启动的时候,使用异步线程解析这些布局,等需要使用的时候直接从内存中拿来用. 造成内存泄漏的原因,需要先分析View的post方法执行流程,也就是文章前半部分的内容 文章内容: View#post方法作用以及实

Android 内存泄漏总结

Java中的内存泄漏 java内存泄漏大家都不陌生了,简单粗俗的讲,就是该被释放的对象没有释放,一直被某个或某些实例所持有却不再被使用导致 GC 不能回收.在Java中,内存泄漏就是存在一些被分配的对象,这些对象有下面两个特点,首先,这些对象是可达的,即在有向图中,存在通路可以与其相连:其次,这些对象是无用的,即程序以后不会再使用这些对象.如果对象满足这两个条件,这些对象就可以判定为Java中的内存泄漏,这些对象不会被GC所回收,然而它却占用内存. 在C++中,内存泄漏的范围更大一些.有些对象被

Android内存管理分析

大部分因为工作任务繁重,一般我们很少关心内存的事,只知道先把任务完成.只有真正到了发现UI卡顿 或者APP实在跑不下去了(一点一卡),才会考虑到内存优化.或者你所在的大公司比较关心手机运行流利程度,也需要对内存进行管理. 1.内存管理的基础知识 因为安卓的顶层也是 Java来实现的,作为客户顿的程序员应该懂得如何去管理内存. 又因为Java不像C语言可以执行free去主动释放内存,而是提供了一套Java的垃圾处理器.但是该处理器并不能时刻盯着内存,在内存不需要的时候直接清理(程序员比较方便,但是

Android内存泄漏

韩梦飞沙  韩亚飞  [email protected]  yue31313  han_meng_fei_sha #Android 内存泄漏总结 内存管理的目的就是让我们在开发中怎么有效的避免我们的应用出现内存泄漏的问题.内存泄漏大家都不陌生了,简单粗俗的讲,就是该被释放的对象没有释放,一直被某个或某些实例所持有却不再被使用导致 GC 不能回收.最近自己阅读了大量相关的文档资料,打算做个 总结 沉淀下来跟大家一起分享和学习,也给自己一个警示,以后 coding 时怎么避免这些情况,提高应用的体验