Android中的内存泄漏以及具体案例分析

一.内存泄漏的本质:

长生命周期的对象持有短生命周期对象的引用,导致GC无法回收短生命周期的对象。

二.Android中常见的内存泄漏的场景:

1.集合类:

全局集合类强引用没清理会造成内存泄漏(特别是 static 修饰的集合)。

2.静态成员变量:

静态成员变量的生命周期=应用程序的生命周期,如果静态成员变量持有生命周期短的对象引用,会导致内存泄漏。

3.单例类:

单例类的生命周期=应用程序的生命周期,如果单例持有生命周期短的对象引用,会导致内存泄漏。

(1)单例持有了activity的引用。

3.非静态内部类/匿名内部类:

非静态内部类/匿名内部类会持有外部类的引用,如果非静态内部类/匿名内部类的生命周期比外部类的生命周期长的话,会导致内存泄漏。

(1)非静态/匿名Handler持有activity的引用。

(2)非静态/匿名Thread持有activity的引用。

4.资源类:

资源对象用完没关闭造成的内存泄漏、监听器等注册之后没有解注册。eventsbus。

(1)广播没有解注册

//广播的注册和解注册要成对并且要在对应的生命周期进行注册/解注册
unregisterReceiver(receiver);

(2)文件流没有关闭

inputStream / outputStream.close()

(3)cursor(游标)没有关闭

cursor.close

(4)图片资源没有回收

//图片资源在使用完要记得回收
biamap.recycler();
bitmap=null;

(5)动画资源启动之后没有停止

animation.cancel();

5.其它
(1)Activity 的 Context 造成的泄漏,可以使用 ApplicationContext。

三.Android中常见的内存泄漏的案例分析:

1.集合类:

 如案例所示,只是简单地将使用对象使用完之后置空是不行的,还需要将这个集合中的元素在集合不需要使用的时候里面元素置空以及集合置空。

public class MainActivity extends AppCompatActivity {
    //集合类,尤其是static的
    static List<Object> testList = new ArrayList<>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //往集合类中存放数据
        for (int i = 0; i < 10; i++) {
            Object object = new Object();
            testList.add(object);
            //这里将对象在使用完之后置空
            object = null;
        }
    }
}

  改进如下:

public class MainActivity extends AppCompatActivity {
    //集合类,尤其是static的
    static List<Object> testList = new ArrayList<>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //往集合类中存放数据
        for (int i = 0; i < 10; i++) {
            Object object = new Object();
            testList.add(object);
            //这里将对象在使用完之后置空
            object = null;
        }
        //在集合使用完毕之后,需要对集合以及集合内元素进行置空
        testList.clear();
        testList = null;
    }
}
 

3.非静态内部类/匿名内部类:

(1)非静态/匿名Handler持有外部activity的引用。

如案例所示,由于匿名内部类/非静态内部类默认持有外部类的引用,会导致外部类即使在不使用的情况下也没办法释放。

public class MainActivity extends AppCompatActivity {

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

    //匿名内部类
    Handler handler = new Handler() {
        @Override
        public void handleMessage(@NonNull Message msg) {
            super.handleMessage(msg);
            // TODO: 2024/3/18 0018  
        }
    };

    //非静态内部类
    private class TestHandler extends Handler {
        @Override
        public void handleMessage(@NonNull Message msg) {
            super.handleMessage(msg);
            // TODO: 2024/3/18 0018  
        }
    }
}

改进方案1:Activity销毁时,清空Handler中未执行或正在执行的Callback以及Message。

public class MainActivity extends AppCompatActivity {

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

    //匿名内部类
    Handler handler = new Handler() {
        @Override
        public void handleMessage(@NonNull Message msg) {
            super.handleMessage(msg);
            // TODO: 2024/3/18 0018
        }
    };


    @Override
    protected void onDestroy() {
        super.onDestroy();
        //移除所有的callBack和message
        handler.removeCallbacksAndMessages(null);
    }
}

改进2:采用静态内部类+弱引用的写法。

public class MainActivity extends AppCompatActivity {

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

    //非静态内部类
    private static class TestHandler extends Handler {
        //虚引用
        WeakReference<Activity> mActivity;

        //构造函数
        TestHandler(Activity activity) {
            mActivity = new WeakReference<>(activity);
        }

        @Override
        public void handleMessage(@NonNull Message msg) {
            super.handleMessage(msg);
            // TODO: 2024/3/18 0018
        }
    }
}

改进3:将非静态内部类抽出去写一个类

四.如何防止内存泄漏:

1、尽量使用Application的Context而不是Activity的
2、使用弱引用或者软引用
3、手动设置null,解除引用关系
4、将内部类设置为static,不隐式持有外部的实例
5、注册与反注册成对出现,在对象合适的生命周期进行反注册操作。
6、如果没有修改的权限,比如系统或者第三方SDK,可以使用反射进行解决持有关系
7、在使用完BraodcastReceiver,ContentObserver,File,Cursor,Stream,Bitmap等资源时,一定要在Activity中的OnDestry中及时的关闭、注销或者释放内存

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值