关于Android内存泄漏的种种总结第二弹

衔接上篇:
新年事后献上关于Android内存泄漏的种种总结
顺手留下GitHub连接,须要获取相关面试等内容的能够本身去找
https://github.com/xiangjiana/Android-MS
(VX:mm14525201314)git

在Android应用的开发中,为了防止内存溢出,在处理一些占用内存大并且声明周 期较长的对象时候,能够尽可能应用软引用和弱引用技术。github

软/弱引用能够和一个引用队列(ReferenceQueue)联合使用,若是软引用所引用 的对象被垃圾回收器回收,Java虚拟机就会把这个软引用加入到与之关联的引用队 列中。利用这个队列能够得知被回收的软/弱引用的对象列表,从而为缓冲器清除已 失效的软/弱引用。 面试

假设咱们的应用会用到大量的默认图片,好比应用中有默认的头像,默认游戏图标 等等,这些图片不少地方会用到。若是每次都去读取图片,因为读取文件须要硬件 操做,速度较慢,会致使性能较低。因此咱们考虑将图片缓存起来,须要的时候直 接从内存中读取。可是,因为图片占用内存空间比较大,缓存不少图片须要不少的 内存,就可能比较容易发生OutOfMemory异常。这时,咱们能够考虑使用软/弱引 用技术来避免这个问题发生。数组

如下就是高速缓冲器的雏形: 首先定义一个HashMap,保存软引用对象。缓存

private Map <String, SoftReference<Bitmap>> imageCache = new Has 
  hMap <String, SoftReference<Bitmap>> ();

再来定义一个方法,保存Bitmap的软引用到HashMap
关于Android内存泄漏的种种总结第二弹
使用软引用之后,在OutOfMemory异常发生以前,这些缓存的图片资源的内存空间 能够被释放掉的,从而避免内存达到上限,避免Crash发生。 若是只是想避免OutOfMemory异常的发生,则可使用软引用。架构

若是对于应用的性 能更在乎,想尽快回收一些占用内存比较大的对象,则可使用弱引用。 app

另外能够根据对象是否常用来判断选择软引用仍是弱引用。若是该对象可能会 常用的,就尽可能用软引用。若是该对象不被使用的可能性更大些,就能够用弱 引用ide

ok,继续回到主题。前面所说的,建立一个静态Handler内部类,而后对 Handler 持有的对象使用弱引用,这样在回收时也能够回收 Handler 持有的对象,可是这样 作虽然避免了 Activity 泄漏,不过 Looper 线程的消息队列中仍是可能会有待处理的 消息,因此咱们在 Activity 的 Destroy 时或者 Stop 时应该移除消息队列 MessageQueue中的消息。 oop

下面几个方法均可以移除 Message:性能

public final void removeCallbacks(Runnable r); 
  public final void removeCallbacks(Runnable r, Object token); 
  public final void removeCallbacksAndMessages(Object token); 
  public final void removeMessages(int what); 
  public final void removeMessages(int what, Object object);
  • 尽可能避免使用 static 成员变量
    若是成员变量被声明为 static,那咱们都知道其生命周期将与整个app进程生命 周期同样。

    这会致使一系列问题,若是你的app进程设计上是长驻内存的,那即便app切到 后台,这部份内存也不会被释放。按照如今手机app内存管理机制,占内存较 大的后台进程将优先回收,由于若是此app作过进程互保保活,那会形成app在 后台频繁重启。当手机安装了你参与开发的app之后一晚上时间手机被消耗空了 电量、流量,你的app不得不被用户卸载或者静默。 这里修复的方法是:

不要在类初始时初始化静态成员。能够考虑lazy初始化。 架构设计上要思考是否真 的有必要这样作,尽可能避免。若是架构须要这么设计,那么此对象的生命周期你有 责任管理起来。

  • 避免 override finalize()
    一、finalize 方法被执行的时间不肯定,不能依赖与它来释放紧缺的资源。时间 不肯定的缘由是:
  • 虚拟机调用GC的时间不肯定
  • Finalize daemon线程被调度到的时间不肯定

二、finalize 方法只会被执行一次,即便对象被复活,若是已经执行过了 finalize 方法,再次被 GC 时也不会再执行了,缘由是:
含有 finalize 方法的 object 是在 new 的时候由虚拟机生成了一个 finalize reference 在来引用到该Object的,而在 finalize 方法执行的时候,该 object 所 对应的 finalize Reference 会被释放掉,即便在这个时候把该 object 复活(即用 强引用引用住该 object ),再第二次被 GC 的时候因为没有了 finalize reference 与之对应,因此 finalize 方法不会再执行。

三、含有Finalize方法的object须要至少通过两轮GC才有可能被释放。

  • 资源未关闭形成的内存泄漏
    对于使用了BraodcastReceiverContentObserver,File,游标 Cursor, Stream,Bitmap等资源的使用,应该在Activity销毁时及时关闭或者注销,否 则这些资源将不会被回收,形成内存泄漏。
  • 一些不良代码形成的内存压力
    有些代码并不形成内存泄露,可是它们,或是对没使用的内存没进行有效及时 的释放,或是没有有效的利用已有的对象而是频繁的申请新内存。

好比:
构造 Adapter 时,没有使用缓存的 convertView ,每次都在建立新的 converView。这里推荐使用 ViewHolder

总结:

  • 对 Activity 等组件的引用应该控制在 Activity 的生命周期以内; 若是不能就考 虑使用 getApplicationContext 或者 getApplication,以免 Activity 被外部长 生命周期的对象引用而泄露。
  • 尽可能不要在静态变量或者静态内部类中使用非静态外部成员变量(包括context ),即便要使用,也要考虑适时把外部成员变量置空;也能够在内部类中使用弱 引用来引用外部类的变量。
  • 对于生命周期比Activity长的内部类对象,而且内部类中使用了外部类的成员变 量,能够这样作避免内存泄漏:
    • 将内部类改成静态内部类
    • 静态内部类中使用弱引用来引用外部类的成员变量
  • Handler 的持有的引用对象最好使用弱引用,资源释放时也能够清空 Handler 里面的消息。好比在 Activity onStop 或者 onDestroy 的时候,取消掉该 Handler对象的 MessageRunnable.
  • 在 Java 的实现过程当中,也要考虑其对象释放,最好的方法是在不使用某对象 时,显式地将此对象赋值为 null,好比使用完Bitmap 后先调用 recycle(),再赋 为null,清空对图片等资源有直接引用或者间接引用的数组(使用 array.clear() ; array = null)等,最好遵循谁建立谁释放的原则。
  • 正确关闭资源,对于使用了BraodcastReceiverContentObserver,File,游 标 Cursor,Stream,Bitmap等资源的使用,应该在Activity销毁时及时关闭或 者注销。
  • 保持对对象生命周期的敏感,特别注意单例、静态对象、全局性集合等的生命 周期。

删减了一部分,见谅^_^
顺手留下GitHub连接,须要获取相关面试等内容的能够本身去找
https://github.com/xiangjiana/Android-MS
(VX:mm14525201314)
关于Android内存泄漏的种种总结第二弹

相关文章
相关标签/搜索