内存泄漏和使用工作线程常见方式总结

内存泄漏

1.类的静态变量持有大数据对象 静态变量长期维持到大数据对象的引用,阻止垃圾回收。还有一些静态的Activity,静态的View

2.非静态内部类存在静态实例 非静态内部类会维持一个到外部类实例的引用,如果非静态内部类的实例是静态的,就会间接长期维持着外部类的引用,阻止被回收掉。

3.对于使用了BraodcastReceiver,ContentObserver,File,Cursor,Stream,Bitmap等资源的使用,应该在Activity销毁时及时关闭或者注销,否则这些资源将不会被回收,造成内存泄漏。 解决办法使用try catch Finally 里面关闭它,或者用带资源的try()将资源初始化写在括号里面。,不过据了解现在Bitmap不用手动调用recycle,垃圾回收器会自动回收,因为手动调用的话很可能会造成其他地方调用了被回收Bitmap,非要手动的话用引用计数法

4.Handler内存泄漏 Handler作为内部类存在于Activity中,但是Handler生命周期与Activity生命周期往往并不是相同的,比如当Handler对象有Message在排队,则无法释放,进而导致本该释放的Acitivity也没有办法进行回收。 解决办法:声明handler为static类,这样内部类就不再持有外部类的引用了,就不会阻塞Activity的释放 ,如果内部类实在需要用到外部类的对象,可在其内部声明一个弱引用引用外部类。

public class MainActivity extends Activity {
 private CustomHandler mHandler;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
     super.onCreate(savedInstanceState);
     mHandler = new CustomHandler(this);
 }

 static class CustomHandlerextends Handler {
     // 内部声明一个弱引用,引用外部类
     private WeakReference<MainActivity > activityWeakReference;
     public MyHandler(MyActivity activity) {
         activityWeakReference= new WeakReference<MainActivity >(activity);
     }
             // ... ...   
}

5.不要在onDraw里面或者onMeasure创建对象,这样会造成频繁GC
6.单例模式造成的内存泄漏

public class AppManager {

    private static AppManager instance;
    private Context context;

    private AppManager(Context context) {
        this.context = context;
        //应该改成
        this.context = context.getApplicationContext();
    }

    public static AppManager getInstance(Context context) {

        if (instance != null) {
            instance = new AppManager(context);
        }
        return instance;

    }

}

由于生命周期不一样,如果传进来的是Activity的Context,会造成Activity无法回收造成内存泄漏,解决办法就是用Application的Context
7.线程造成内存泄漏

        new AsyncTask<Void, Void, Void>() {

            @Override
            protected Void doInBackground(Void... params) {
                SystemClock.sleep(10000);
                return null;
            }
        }.execute();


        new Thread(new Runnable() {
            @Override
            public void run() {
                SystemClock.sleep(10000);
            }
        }).start();

上面两种情况都会造成内存泄漏,因为匿名内部类都是默认持有外部引用的,如果再Activity关闭时线程工作还没有做完,将可能造成内存泄漏,和之前handler其实属于差不多算是同类问题,也是使用静态内部类+弱引用来解决

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);
        }
    }

    new Thread(new MyRunnable()).start();
    new MyAsyncTask(this).execute();

总结:只要是匿名内部类都会持有外部引用,这时候就要考虑是否会造成内存泄漏了

常见工作线程方式

1直接单个线程

public class MyRunnable implements Runnable {

    @Override
    public void run() {
    //耗时操作
    }

    public void startThread() {
        MyRunnable myRunnable = new MyRunnable();
        Thread thread = new Thread(myRunnable);
        thread.start();
    }
}

2.线程池
常见有四种线程池

Executors.newFixedThreadPool(3);//固定大小线程池
Executors.newCachedThreadPool();//可变大小线程池
Executors.newSingleThreadExecutor();//串行线程池
Executors.newScheduledThreadPool(int corePoolSize)//定期循环执行任务线程池

当然也可以定义线程池

public class SimpleExecutor implements Executor {
    @Override
    public void execute(Runnable command) {
        new Thread(command).start();
    }
}

3.HandlerThread是一个集成了Looper和MessageQueue的线程,当启动HandlerThread时,会同时生成Looper和MessageQueue,然后等待消息进行处理.常见用法

public class ThreadDemo extends Activity {  
 private static final String TAG = "bb";    
    private int count = 0;    
    private Handler mHandler ;    

    private Runnable mRunnable = new Runnable() {    
        public void run() {    
            //为了方便 查看,我们用Log打印出来    
            Log.e(TAG, Thread.currentThread().getId() + " " +count);    
            count++;    
//            setTitle("" +count);    
            //每2秒执行一次    
            mHandler.postDelayed(mRunnable, 2000);    
        }    
    };    
    @Override    
    public void onCreate(Bundle savedInstanceState) {    
     Log.e(TAG, "Main id    "+Thread.currentThread().getId() + " " +count);    
        super.onCreate(savedInstanceState);    
        setContentView(R.layout.main);     
        //通过Handler启动线程    
        HandlerThread handlerThread = new HandlerThread("threadone");//创建一个handlerThread线程  
        handlerThread.start();//启动该线程  
        mHandler =  new Handler(handlerThread.getLooper());//设计handler的looper
        mHandler.post(mRunnable); //加入mRunnable线程体到子线程的消息队列  


    }    
    @Override    
    protected void onDestroy() {    
        //将线程与当前handler解除  
        mHandler.removeCallbacks(mRunnable);    
        super.onDestroy();    
    }    
}  
  1. AsyncQueryHandler是用于在ContentProvider上面执行异步的CRUD操作的工具类,CRUD操作会被放到一个单独的子线程中执行,当操作结束获取到结果后,将通过消息的方式传递给调用AsyncQueryHandler的线程,通常就是主线程。AsyncQueryHandler是一个抽象类,集成自Handler,通过封装ContentResolver、HandlerThread、AsyncQueryHandler等实现对ContentProvider的异步操作。
    最简单的demo
AsyncQueryHandler asyncQueryHandler = new AsyncQueryHandler(activity.getContentResolver()){

        @Override
        protected void onInsertComplete(int token, Object cookie, Uri uri) {
            super.onInsertComplete(token, cookie, uri);
            Log.d(TAG, "onInsertComplete  return uri: " + uri);
        }

 };

 asyncQueryHandler.startInsert(-1, null, mUri, values);

查询,更新也是一样的,第一个参数为识别码,只要对应的在OnXXXXCompelete方法里面对应switch就可以了
5. IntentService具有Service一样的生命周期,同时也提供了在后台线程中处理异步任务的机制
继承OnHandleIntent方法,通过intent来携带数据

ublic class SimpleIntentService extends IntentService {


    public SimpleIntentService() {
        super(SimpleIntentService.class.getName());
        setIntentRedelivery(true);
    }
    @Override
    protected void onHandleIntent(Intent intent) {
        //该方法在后台调用,这里可以拿到intent所携带的数据
    }
}

6.AsyncTask是在Executor框架基础上进行的封装,官方文档说这个不适合长时间的操作,简单用法如下

public class FullTask extends AsyncTask<String,String,String> {

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        //主线程执行
    }

    @Override
    protected String doInBackground(String... params) {
        return null;
        //子线程执行
    }

    @Override
    protected void onProgressUpdate(String... values) {
        super.onProgressUpdate(values);
        //主线程执行
    }

    @Override
    protected void onPostExecute(String s) {
        super.onPostExecute(s);
        //主线程执行
    }

    @Override
    protected void onCancelled() {
        super.onCancelled();
        //主线程执行
    }

}

7.Loader是Android3.0开始引入的一个异步数据加载框架
这里写图片描述
官方文档详见:Loader官方文档

区别:
这里写图片描述

切换回主线程方法

EventBus,runOnUithread()

主要参考链接

链接1
链接2

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值