什么情况导致内存泄漏?

内存泄漏是生命周期较长的对象持有生命周期较短的对象的所引用

举个例子,如果一个 Activity 被一个单例对象所引用,那么当退出这个 Activity 时,由于单例的对象依然存在(单例对象的生命周期跟整个 App 的生命周期一致),而单例对象又持有 Activity 的引用,这就导致了此 Activity 无法被回收,从而造成内存泄漏。

  • 单例造成的内存泄漏

    单例对象中有Context引用,这个Context不应该是Activity,而应该是applicationContext引用,这样就不会造成内存泄漏。

  • 非静态内部类造成的内存泄漏

    非静态内部类会默认持有外部类的应用。此时,如果这个内部类的实例是静态实例,则会与整个app的生命周期相同,当外部类生命周期结束时,还被内部类引用,则无法被回收,造成内存泄漏。

    解决办法:使内部类的实例不为静态实例或者使内部类变为静态内部类(不会持有外部类的引用)。

  • Handler 或 Runnable 作为非静态内部类

    handler 和 runnable 都有定时器的功能,当它们作为非静态内部类的时候,同样会持有外部类的引用,如果它们的内部有延迟操作,在延迟操作还没有发生的时候,销毁了外部类,那么外部类对象无法回收,从而造成内存泄漏。

    解决办法:把 Handler 和 Runnable 定义为静态内部类,这样它们就不再持有 MainActivity 的引用了,从而避免了内存泄漏,最好再在 onDestory 调用 handler 的 removeCallbacks 方法来移除 Message。

  • 其他的内存泄漏情况

    比如 BraodcastReceiver 未取消注册,InputStream 未关闭等,这类内存泄漏非常简单,只要在平时写代码时多多注意即可避免。

  • MVP架构中的内存泄漏

    Presenter持有iview的引用,在activity/fragment生命周期结束后,presenter还在做耗时操作就会出现内存泄漏。

    解决办法:在activity/fragment的onDestroy()方法中将presenter的view对象置空,使得presenter不再持有activity/fragment的引用。