Android 内存泄漏总结

前言:

内存泄漏(Memory Leak):是指程序中已动态分配的堆内存由于某种原因程序未释放或无法释放导致而导致的系统内存被持续占用,导致程序的运行速度减慢甚至系统崩溃(OOM)等严重后果。

Android造成内存泄漏常见场景

静态变量

由于静态变量【存在于JVM内存】的生命周期会伴随一个.class文件从加载到卸载的全过程,当被static修饰的类,持有Activity等对象的引用时会导致界面无法正常销毁等异常场景。

标注:java类的完整生命:1、加载 2、连接 3、初始化 4、使用 5、卸载

单例模式

静态变量导致的内存泄漏往往比较明显,而单例模式所导致的内存泄漏一般比较容易被我们所忽视,由于在Android端单例的生命周期和Application的生命周期相同,导致单例模式在持有外部引用的过程中可能造成内存泄漏。

 private SingleInstance() {}

    private static volatile SingleInstance mInstance = null;

    private static SingleInstance getInstance() {
        if (null == mInstance) {
            synchronized (SingleInstance.class) {
                if (mInstance == null) {
                    mInstance = new SingleInstance();
                }
            }
        }
        return mInstance;
    }
private List<OnSingleInstanceListener> mList = new ArrayList<>();

    public void addListener(OnSingleInstanceListener listener) {
        mList.add(listener);
    }

    public interface OnSingleInstanceListener {
        void onSingleInstanceListener();
    }
public class MainActivity extends AppCompatActivity implements OnSingleInstanceListener {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        System.currentTimeMillis();

        SingleInstance.getInstance().addListener(this);
    }

由代码可见,当使用单例模式时会出现SingleInstance持有接口实现对象的引用,导致接口实现类对象【MainActivity】的生命周期释放无法正常执行。

常见其他造成内存泄漏的场景

1.单例造成的内存泄漏
2.非静态内部类创建静态实例造成的内存泄漏
3.Handler造成的内存泄漏
4.线程造成的内存泄漏
5.资源未关闭造成的内存泄漏
6.使用ListView时造成的内存泄漏
7.集合容器中的内存泄漏
8.WebView造成的泄漏
9. 属性动画所引起的内存泄漏

针对以上几条中,Handler的内存泄漏可以从两方面入手分析,Android层面和Java层面,当Android应用程序启动时,应用程序的主线程【MainThread】会调用Looper对象方法创建Looper轮巡器并将与之关联的MessageQueue关联起来,所有发送给MessageQueue的Message都会持有Handler的引用【Message.target】,所以Looper会回调Handler的handleMessage()方法处理消息。只要MessageQueue中有未处理的Message,Looper就会不断的从中取出并交给Handler处理。主线程的Looper对象会伴随该应用程序的整个生命周期。而从Java层面分析在Java中,非静态内部类和匿名内部类都会潜在持有它们所属的外部类的引用,从而导致生命周期的异常,就可能会引起我们常见的Activity无法被垃圾回收所引起的内存泄漏。而一般的解决方法就是将Handler类独立出来或者使用静态内部类从而避免内存泄漏。而线程类出现内存泄漏也大都是使用了匿名内部类持有其所在Activity的隐式引用,最终导致内存泄漏。

关于集合容器中的内存泄漏我们再避免内存泄漏时往往采取的做法是将集合变量置Null,但是在将List或Map置Null的同时并不能保证触发GC回收,GC回收与finalize()有关。

参考:
如果对象在进行可达性分析后发现没有与GC Roots相连接的引用链,那它将会被第一次标记并且进行一次筛选,筛选的条件是此对象是否有必要执行finalize()方法。当对象没有覆盖finalize()方法,或者finalize()方法已经被虚拟机调用过,虚拟机将这两种情况都视为“没有必要执行”。如果这个对象被判定为有必要执行finalize()方法,那么这个对象将会放置在一个叫做F-Queue的队列之中,并在稍后由一个由虚拟机自动建立的、低优先级的Finalizer线程去执行它。这里所谓的“执行”是指虚拟机会触发这个方法,但并不承诺会等待它运行结束,这样做的原因是,如果一个对象在finalize()方法中执行缓慢,或者发生了死循环(更极端的情况),将很可能会导致F-Queue队列中其他对象永久处于等待,甚至导致整个内存回收系统崩溃。finalize()方法是对象逃脱死亡命运的最后一次机会,稍后GC将对F-Queue中的对象进行第二次小规模的标记,如果对象要在finalize()中成功拯救自己——只要重新与引用链上的任何一个对象建立关联即可,譬如把自己(this关键字)赋值给某个类变量或者对象的成员变量,那在第二次标记时它将被移除出“即将回收”的集合;如果对象这时候还没有逃脱,那基本上它就真的被回收了。

Android 内存泄漏检测工具

1.Profiler
2.Android LeakCanary
3.MAT

Profiler

Memory Profiler是Android Profiler中的一个组件,Android Profiler是Android Studio3.0用来替换之前Android Monitor的观察工具,主要用来观察内存,网络,cpu温度等。它能够让你识别出来内存泄漏和内存抖动,导致应用卡顿,ANR和Crash. 可以展示一个内存使用的真实图表,让你知道当时内存使用情况,还能强制内存回收,和跟踪内存分配。

Android LeakCanary

Leakcanary是square公司开源的一款内存监测框架,直接在Application中使用,然后运行APP就会自动检测,检测到会在另一个APP上通知,显示详情。

MAT

MAT:输入HRPOF文件,输出分析结果

  • Histogram:查看不同类型对象及其大小
  • DominateTree:对象占用内存及其引用关系

后期详解对于三个工具的使用方式。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值