一.介绍
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        }  }  

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

四.内存分析
不管是对内存使用情况的分析,还是排查内存泄露,我都推荐
去好好看看以下大神的文章,相信看过后,会有很大的收获,我就是如此=。=

  • android 中如何分析内存泄露
  • Android最佳性能实践(二)——分析内存的使用情况

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

更多相关文章

  1. 第八章 网络的时代—网络开发(3)
  2. android里的线程和进程
  3. Android中线程与进程的理解
  4. Android(安卓)避免内存泄漏(译)
  5. Android中图片的三级缓存策略
  6. Android(安卓)Dev Guide 中文版二 (原创,请注明出处)未完待续
  7. Android通讯录开发之解决快速搜索联系人线程同步问题
  8. Android(安卓)Ashmem相关介绍
  9. Android(安卓)性能监测工具,优化内存、卡顿、耗电、APK的方法

随机推荐

  1. android 拨打电话
  2. Android 开源项目集合
  3. android中生成和使用jar 分享
  4. Android学习笔记(2)——搭建Android开发
  5. android DragLayer源码
  6. android关于socket编程,以聊天为例http:/
  7. Android - 按钮组件详解
  8. Android提供的LruCache类简介
  9. android的返回键弹出dialog
  10. Android Device Monitor工具的使用