Android 内存泄露与优化,以及MAT工具

一.介绍

Android机器中,内存使用问题一直是个十分重要,引人注目的问题,当我们代码编写不当,或者逻辑没处理好,就会导致机器运行缓慢,有时候甚至死机。对于程序员来说,这很致命,所以要去理解内存的使用,去避免内存的泄露,不断优化内存,而当出现内存泄露导致的问题,我们能够分析log,并且会用工具MAT。

二.什么场景会导致内存泄露

内存泄露其实就是占用内存的对象使用后没有被回收。在这种现象下,当java程序运行一段时间,占用的内存越来越大,导致该进程的内存占用达到Android为进程分配的内存使用上限,程序就死了。

  1. ListView、GridView等在使用适配器时,没有使用ConvertView缓存
  2. Bitmap使用后没有释放
  3. Context泄露,Context的引用超过了本身的生命周期。比如一个长时间在跑的异步任务或者长时间的对象,拥有着Activity(Context类型)的引用,这时Activity被销毁了,但是内存依然存在,Context无法被回收。所以这种情况下,应使用getApplicationContext比较好
  4. 数据库游标或者文件流缓存等使用后未关闭
  5. 线程使用不当。在线程中的run函数处理着耗时的工作,当设备横竖屏切换,重新创建Activity,由于run函数未处理完,导致引用的Activity也不会被销毁。再说AsyncTask,由于运行机制ThreadPoolExcutor,生命周期更加不可控,更容易出现问题了(具体解决方法,可看下面讲解)。

三.内存优化注意点

1.图片优化

在Android中显示Bitmap图片,会造成一定的内存消耗,甚至会导致OOM异常爆发,所以对于图片的显示,要做一定的处理。

  • 大图片显示要进行压缩才能加载。一张图片,不要认为表面的小而不以为然,比如一张150kb的图片,当读到内存时,若该图片像素为2048*1024,使用属性为ARGB_8888(默认),也就是一个像素4byte,那么总内存就是4*2048*1024byte,8M多。可见,大图片压缩加载的必要性。具体压缩详细方法可见 Android高效加载大图,防止OOM,以及多图解决方案
  • 多图显示时要活用内存缓存技术。在一个ListView(或GridView)中,不断加载图片,不可能一直把图片都到内存中,因为内存是有上限值的,也要为其他操作分配内存。所以当在可见区域里,要将移除屏幕的部分内存进行回收处理。可若移除的部分在下个操作中又要马上使用,这时若被移除回收,性能效率马上就下去了,所以可以使用LRUCache缓存技术。具体可见以上那篇博文。
  • ListView中的快速滑动加载图片,在不影响使用体验的情况下,应判断滑动状态进行加载操作。在快速滑动时,由于滑动过程中加载的资源是不会被使用的,反而影响了用户所要查看资源的加载,所以在快速滑动(SCROLL_STATE_TOUCH_SCROLL)列表时,就不再去获取加载资源了,在静止(SCROLL_STATE_IDLE)以及触摸屏幕(SCROLL_STATE_TOUCH_SCROLL)时才去加载,我们需要注册一个滚动监听器OnScrollListener 。

2.线程、异步任务优化

因为线程、异步任务等生命周期的不可控性,成为了内存泄露的另一个源头。平常中,因为对它的频繁使用,所以,我们应慎重对待它。

  • 在Activity结束时,应及时销毁所创建的线程。不然,当线程持有该所在Activity的引用时,实际上以为退出去的Activity,其实由于线程未完成,所引用的老Activity是不会被销毁的,就出现了内存泄露,所以可使用Thread.interrupt()中断线程,虽然并不是真正意义上的中断!具体详细可见 Thread的中断机制(interrupt)
  • AsyncTask异步任务的生命周期不可控性。一定得注意一件事,因为平常喜欢在Activity中创建AsyncTask作为内部类,完成一些耗时且Ui交互的操作,十分方便,但是其实这个是具有很大风险的,因为很容易出现内存泄露。异步任务内部是以ThreadPoolExcutor作为实现机制的,这样出来的线程对象生命周期是不确定的!!网上有人给出两个解决方案:1.将线程的内部类改为静态内部类(没试过,不知道效果) 2.在线程内部采用弱引用保存Context引用。即如下代码所示:
     public abstract class WeakAsyncTask<Params, Progress, Result, WeakTarget> extends  AsyncTask<Params, Progress, Result> {
    protected WeakReference<WeakTarget> mTarget;  

    public WeakAsyncTask(WeakTarget target) {
        mTarget = new WeakReference<WeakTarget>(target);
    }  

    /** {@inheritDoc} */
    @Override
    protected final void onPreExecute() {
        final WeakTarget target = mTarget.get();
        if (target != null) {
            this.onPreExecute(target);
        }
    }  

    /** {@inheritDoc} */
    @Override
    protected final Result doInBackground(Params... params) {
        final WeakTarget target = mTarget.get();
        if (target != null) {
            return this.doInBackground(target, params);
        } else {
            return null;
        }
    }  

    /** {@inheritDoc} */
    @Override
    protected final void onPostExecute(Result result) {
        final WeakTarget target = mTarget.get();
        if (target != null) {
            this.onPostExecute(target, result);
        }
    }  

    protected void onPreExecute(WeakTarget target) {
        // No default action
    }  

    protected abstract Result doInBackground(WeakTarget target, Params... params);  

    protected void onPostExecute(WeakTarget target, Result result) {
        // No default action
       }
}

可能内存优化方面,还有很多方面需要补足,还需努力。

四.内存分析

不管是对内存使用情况的分析,还是排查内存泄露,我都推荐

去好好看看以下大神的文章,相信看过后,会有很大的收获,我就是如此=。=

在此记录,以备日后再读。

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-07-29 00:36:26

Android 内存泄露与优化,以及MAT工具的相关文章

android内存泄漏检测StrictMode和MAT工具使用

StrictMode说明 Android 2.3提供一个称为严苛模式(StrictMode)的调试特性,Google称该特性已经使数百个Android上的Google应用程序受益.那它都做什么呢?它将报告与线程及虚拟机相关的策略违例.一旦检测到策略违例(policy violation),你将获得警告,其包含了一个栈trace显示你的应用在何处发生违例.你可以强制用警告代替崩溃(crash),也可以仅将警告计入日志,让你的应用继续执行.策略的细节尚难确定,可以期待随Android的成熟Googl

android内存泄露调试,Heap,MAT

三.内存监测工具 DDMS --> Heap 无论怎么小心,想完全避免bad code是不可能的,此时就需要一些工具来帮助我们检查代码中是否存在会造成内存泄漏的地方.Android tools中的DDMS就带有一个很不错的内存监测工具Heap(这里我使用eclipse的ADT插件,并以真机为例,在模拟器中的情况类似).用Heap监测应用进程使用内存情况的步骤如下: 1. 启动eclipse后,切换到DDMS透视图,并确认Devices视图.Heap视图都是打开的: 2. 将手机通过USB链接至电

android 内存泄露调试

一.概述 1 二.Android(Java)中常见的容易引起内存泄漏的不良代码 1 (一) 查询数据库没有关闭游标 2 (二) 构造Adapter时,没有使用缓存的 convertView 3 (三) Bitmap对象不在使用时调用recycle()释放内存 4 (四) 释放对象的引用 4 (五) 其他 5 三.内存监测工具 DDMS --> Heap 5 四.内存分析工具 MAT(Memory Analyzer Tool) 7 (一) 生成.hprof文件 7 (二) 使用MAT导入.hpro

Android内存泄露总结

Android可能发生内存泄露的地方总结: 1.查询数据库没有关闭游标 2.构建adapter时,没有使用缓存的convertView 3.Bitmap对象不使用的时候调用recycle()方法释放内存 4.释放对象的引用 5.单例模式引用context,如果使用actvitiy-context,会造成内存泄露, 可以使用getApplicationContext()); 或getApplication()代替. 参考文档: A?n?d?r?o?i?d? ?内?存?泄?漏?调?试 http://

Android内存泄露开篇

先来想这三个问题 内存泄露是怎么回事 内存会泄露的原因 避免内存泄露 1.内存泄露怎么回事 一个程序中,已经不需要使用某个对象,但是因为仍然有引用指向它垃圾回收器就无法回收它,当然该对象占用的内存就无法被使用,这就造成了内存泄露. Android的一个应用程序的内存泄露对别的应用程序影响不大. 为了能够使得Android应用程序安全且快速的运行,Android的每个应用程序都会使用一个专有的Dalvik虚拟机实例来运行,它是由Zygote服务进程孵化出来的,也就是说每个应用程序都是在属于自己的进

Android 内存泄露检测工具 LeakCanary 的监控原理

首先回顾一下  java 的几种 reference: 从jdk 1.2 开始,引用分为 强引用,软引用.若引用 和虚引用, 其中 软引用.若引用 和虚引用 和 ReferenceQueue 关联. 在JDK 1.2以前的版本中,若一个对象不被任何变量引用,那么程序就无法再使用这个对象.也就是说,只有对象处于可触及(reachable)状态,程序才能使用它.从JDK 1.2版本开始,把对象的引用分为4种级别,从而使程序能更加灵活地控制对象的生命周期.这4种级别由高到低依次为:强引用.软引用.弱引

Android内存泄露检测工具---LeakCanary的前世今生

曾经检测内存泄露的方式 让我们来看看在没有LeakCanary之前,检测内存泄露的方式 1.Bug收集 通过Bugly.友盟这样的统计平台,统计Bug,了解OutOfMemaryError的情况. 1. 重现问题 对Bug进行筛选,归类,排除干扰项.然后为了重现问题,有时候你必须找到出现问题的机型,因为有些问题只会在特定的设备上才会出现.为了找到特定的机型,可能会想尽一切办法,去买.去借.去求人,去租,商家公司还真干过这事(14年,公司专门派了一个商务去广州找了一家租赁手机的公司,借了50台手机

深度分析内存泄漏原因,使用MAT工具检测内存泄露和性能

造成内存泄漏原因: 场景一:静态变量导致的内存泄漏 例如:mainactivity中 private static context scontext: @override protected void oncreat(bundle savedinstancestate){ ............................................. scontext=this; } 泄漏点:静态变量scontext引用,activity无法正常销毁 场景二:单例模式导致的内存泄漏

Android 内存泄露总结(附内存检测工具)

https://segmentfault.com/a/1190000006852540 主要是分三块: 静态储存区:编译时就分配好,在程序整个运行期间都存在.它主要存放静态数据和常量. 栈区:当方法执行时,会在栈区内存中创建方法体内部的局部变量,方法结束后自动释放内存. 堆区:通常存放 new 出来的对象.由 Java 垃圾回收器回收. 栈与堆的区别 栈内存用来存放局部变量和函数参数等.它是先进后出的队列,进出一一对应,不产生碎片,运行效率稳定高.当超过变量的作用域后,该变量也就无效了,分配给它