安卓内存泄漏那些事

楼主最近学习内存泄漏这块,所以就总结了一下这块的内容笔记

内存泄漏的基础

内存泄漏:内存不在GC掌控之内了。当一个对象已经不需要再使用了,本该被回收时,而有另外一个正在使用的对象持有它的引用从而就导致,对象不能被回收。这种导致了本该被回收的对象不能被回收而停留在堆内存中,就产生了内存泄漏

Tip:我们在开发的时候,为了防止内存溢出,处理一些比较占用内存大并且生命周期长的对象的时候,可以尽量使用软引用和弱引用。 
软引用比LRU算法更加任性,回收量是比较大的,你无法控制回收哪些对象。

下面说一下Android开发中最常见的几个内存泄漏问题:

1.非静态内部类创建的静态实例造成的内存泄漏

有时候因为需求我们会去频繁的启动一个Activity,这时为了避免频繁的创建相同的数据源,我们通常会在Activity中创建了非静态内部类,非静态内部类默认持有Activity类的引用,但是他的生命周期还是和应用程序一样长,所以当Activity销毁时,静态内部类的对象引用不会被GC回收,就会造成了内存溢出,解决办法:

1、将内部类改为静态内部类。

2、将这个内部类封装成一个单例,Context使用Application的Context

2.Handler造成的内存泄漏:

如果把handler写成一个非静态匿名内部类,也会持有Activity的引用,我们知道handler是运行在一个Looper线程中的,而Looper线程是轮询来处理消息队列中的消息的,假设我们处理的消息有十条,而当他执行到第6条的时候,用户点击了back返回键,销毁了当前的Activity,这个时候消息还没有处理完,handler还在持有Activity的引用,这个时候就会导致无法被GC回收,造成了内存泄漏。正确的做法是:

这里不再对经常写错的方法贴出来 ,我们写一下修正过后的写法:


public class MainActivity extends AppCompatActivity {
//new一个自定义的Handler
    private MyHandler mHandler = new MyHandler(this);
    private TextView mTextView ;
 
//自定义静态内部类继承自Handler
    private static class MyHandler extends Handler {
        private WeakReference<Context> reference;
//在构造函数中使用弱引用来引用context对象
        public MyHandler(Context context) {
            reference = new WeakReference<>(context);
        }
        @Override
        public void handleMessage(Message msg) {
            MainActivity activity = (MainActivity) reference.get();
            if(activity != null){
                activity.mTextView.setText("");
            }
        }
    }
  
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mTextView = (TextView)findViewById(R.id.textview);
        loadData();
    }
  
    private void loadData() {
        //...request
        Message message = Message.obtain();
        mHandler.sendMessage(message);
    }
 
@Override
  protected void onDestroy() {
      super.onDestroy();
//移除队列中所有的Runable和消息
//这里也可以使用mHandler.removeMessage和mHandler.removeCallBacks来移除指定的Message和Runable
      mHandler.removeCallbacksAndMessages(null);
  }
}

3.线程造成的内存泄漏

线程使用不恰当造成的内存泄漏也是很常见的,通常我们使用线程都是直接new线程直接使用 不管是同步线程还是异步线程,我们都考虑的太少了,正确做法是引入内部静态类的形式,尽可能使用软引用去执行我们线程

//异步线程
static class MyAsyncTask extends AsyncTask<Void, Void, Void> {
        private WeakReference<Context> weakReference;
  
        public MyAsyncTask(Context context) {
            weakReference = new WeakReference<>(context);
        }
  
        @Override
        protected Void doInBackground(Void... params) {
            SystemClock.sleep(10000);
            return null;
        }
  
        @Override
        protected void onPostExecute(Void aVoid) {
            super.onPostExecute(aVoid);
            MainActivity activity = (MainActivity) weakReference.get();
            if (activity != null) {
                //...
            }
        }
    }
    static class MyRunnable implements Runnable{
        @Override
        public void run() {
            SystemClock.sleep(10000);
        }

 

这样就避免了内存泄漏,当然在Activity销毁时也要记得在OnDestry中调用AsyncTask.cancal()方法来取消相应的任务。避免在后台运行浪费资源。

4、资源未关闭造成的内存泄漏

这个比较常提起,在使用完BraodcastReceiver,ContentObserver,File,Cursor,Stream,Bitmap等资源时,一定要在Activity中的OnDestry中及时的关闭、注销或者释放内存,

否则这些资源不会被GC回收,就会造成内存泄漏。

推荐内存泄漏检测工具:LeakCanary

养成良好的代码习惯,会让你的代码更上一层楼!

by:程序小渣渣

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值