Android中的内存泄漏和内存溢出.md

概念

内存泄漏是因为持有对象长期引用,导致对象无法被 GC 回收。

为了避免这种情况,我们可以选择在对象生命周期结束的时候,解除绑定,将引用置为空,或者使用弱引用。

例子
  1. 单例模式导致内存泄露
    传入的context为act,但单例的生命周期是app
  2. 非静态内部类、匿名内部类导致内存泄露(静态变量持有Act,非静态内部类的静态实例 )
    它们会隐式的持有外部类的引用,长期持有该引用(比如写个循环)就会导致内存泄漏,使用静态内部类和弱引用来代替它们。(因为静态的内部类不会持有外部类的引用)
  3. Handler导致内存泄漏
    Handler通过发送Message与主线程交互,Message发出之后是存储在MessageQueue中的,有些Message也不是马上就被处理的。
    在Message中存在一个 target,是Handler的一个引用,如果Message在Queue中存在的时间越长,就会导致Handler无法被回收。
    如果Handler是非静态的,(因为持有外部activity的引用)会导致Activity或者Service不会被回收。
解决方法 :
  • 静态内部类+弱引用
    创建一个静态Handler内部类,然后对Handler持有的对象使用弱引用)
    静态内部类+弱引用。相当于activity没关闭的时候,act有强弱两种引用,关闭的时候,只有弱引用。
  • 非静态内部类+api clean掉message
  1. 线程造成的内存泄漏
    执行一些长期运行的任务,避免在这些任务中持有 Activity 对象的引用,如果持有了引用的话,我们应该在对象生命周期结束的时候,释放引用。
  2. 资源未关闭造成的内存泄漏
    对于使用了BraodcastReceiver,ContentObserver,File,Cursor,Stream,Bitmap等资源的使用,应该在Activity销毁时及时关闭或者注销,否则这些资源将不会被回收,造成内存泄漏。
LeakCanary

LeakCanary的内存泄露提示一般会包含三个部分:

第一部分(LeakSingle类的sInstance变量)引用第二部分(LeakSingle类的mContext变量), 导致第三部分(MainActivity类的实例instance)泄露.

Java的GC内存回收机制

Android中的内存泄漏和内存溢出.md_第1张图片

当我们向上寻找,一直寻找到GC Root的时候,此对象不会进行回收,例如,一个Activity。那么如果我们向上寻找,直到找到GC Root对象的时候,就说明它是不可以回收的,例如,我定义了一个int a;但是这个数据,我整个页面或者说整个项目都没有用到,则这个对象会被GC掉。

GC的引用点
  1. java栈中引用的对象

  2. 方法静态引用的对象

  3. 方法常量引用的对象

  4. Native中JNI引用的对象

  5. Thread——“活着的”线程

内存溢出
Android中的内存泄漏和内存溢出.md_第2张图片
瞬间大内存:图片加载
内存泄漏和内存溢出区别
  1. 内存溢出是指程序在申请内存的时候,没有足够的内存可以分配,导致Out Of Memory错误,也就是OOM。

  2. 内存泄漏:对象都有生命周期的,在生命周期完成之后,就该被垃圾回收和释放,如果得不到及时的释放,就会一直占用内存,造成内存泄漏。随着内存泄漏的堆积,可能导致oom。

你可能感兴趣的:(Android中的内存泄漏和内存溢出.md)