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

来源:互联网 发布:get it style 综艺 编辑:程序博客网 时间:2024/06/07 21:06

内存泄漏

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

原创粉丝点击