内存泄漏和使用工作线程常见方式总结
来源:互联网 发布: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(); } }
- 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
- 内存泄漏和使用工作线程常见方式总结
- 常见内存泄漏和优化方式 ......
- 内存泄漏常见原因总结
- Android常见内存泄漏和LeakCanary的使用
- 内存泄漏和内存溢出的总结
- Android:Activity,线程,和内存泄漏
- 内存泄漏的原因和处理方式
- 常见内存泄漏原因
- 常见内存泄漏
- Android常见内存泄漏
- 常见的内存泄漏
- 常见内存泄漏分析
- 常见内存泄漏原因
- 常见的内存泄漏
- 内存泄漏2——C++中常见内存泄漏情形总结
- Android 内存溢出和内存泄漏总结----个人总结
- Android的内存机制和常见泄漏情形
- Android的内存机制和常见泄漏情形
- excel科学计数法还原成字符串方法
- Scala入门到精通——第六节:类和对象(一)
- 营销费用预算管理的IT应用之路
- 开发者需要了解的WebKit
- 【spring Mvc】SpringMVC 文件上传配置,多文件上传,使用的MultipartFile
- 内存泄漏和使用工作线程常见方式总结
- LeetCode:Best Time to Buy and Sell Stock
- Centos中vsftpd的安装和配置
- 基于网管针对无线微波设备的管理实施方案
- UntiyShader之深度纹理
- session详细解析(是不是过期、失效时间)
- 【HTML】- HTML和CSS实现下拉菜单
- Socket编程
- c51串口通讯