Android常见内存泄漏及解决方法
2017-08-23 16:22
281 查看
背景
在Android开发中内存泄漏是一个相对来说比较常见的问题,这个问题也相当严重,但是有好多朋友还不知道怎么解决和查看内存泄漏问题,这里就写一篇文章来给大家介绍一些常见的内存泄漏问题以及解决方法。常见内存泄漏
1. 静态引用
比如以下代码,定义了sInstance来传递和使用,会导致MainActivity无法被销毁,这是一种比较低级的错误,一般我们不建议这么使用,如果一定要使用,就需要在最后将sInstance置空。public class MainActivity extends Activity { private static Activity sInstance; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); sInstance = this; } @Override protected void onDestroy() { super.onDestroy(); sInstance = null; } }
2. 内部类持有外部类的引用,内部类被静态引用,等同于外部类被静态引用
在JAVA中内部类的定义与使用一般为成员内部类与匿名内部类,他们的对象都会隐式持有外部类对象的引用,影响外部类对象的回收。GC只会回收没有被引用或者根集不可到达的对象(取决于GC[算法]),内部类在生命周期内始终持有外部类的对象的引用,造成外部类的对象始终不满足GC的回收条件,反映在内存上就是内存泄露。(如,[Android]中Activity的内存泄露)
解决方案为
1.将内部类定义为static
2.用static的变量引用匿名内部类的实例或将匿名内部类的实例化操作放到外部类的静态方法中
public class MainActivity extends Activity { private static TestClass sTestClass; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } @Override protected void onDestroy() { super.onDestroy(); } public class TestClass{ } }
3. AsyncTask
下面的代码我们在退出的时候mAsyncTask是无法被销毁的,会导致Activity无法被销毁:private AsyncTask mAsyncTask; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mAsyncTask = new AsyncTask() { @Override protected Object doInBackground(Object[] objects) { while (true); } }; mAsyncTask.execute(); }
解决办法如下代码:在Activity销毁的时候取消正在运行的AsyncTask
public class MainActivity extends Activity { private AsyncTask mAsyncTask; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mAsyncTask = new AsyncTask() { @Override protected Object doInBackground(Object[] objects) { while (true){ if(isCancelled()){ break; } } return null; } }; mAsyncTask.execute(); } @Override protected void onDestroy() { super.onDestroy(); if(null != mAsyncTask && !mAsyncTask.isCancelled()){ mAsyncTask.cancel(true); } mAsyncTask = null; } }
4. Handle造成的内存泄漏
4.1 用过内部类创建的Handler对象,持有Activity的引用。当执行postDelayed()方法时,会把Handler装入一个Message,并把Message推到MessageQueue中,MessageQueue在一个Looper线程中不断轮询处理消息。因为延迟的时间足够长,当Activity退出时,消息队列还未处理Message,从而引发OOM
public class MainActivity extends Activity { private Handler mHandler = new Handler(){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mHandler.sendEmptyMessageDelayed(0,1000); } }
那么对于上面产生的内存泄漏我们要怎么处理呢?采用弱引用的形式:
public class MainActivity extends Activity { private Handler mHandler; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mHandler = new MyHandler(new WeakReference<Activity>(this)); mHandler.sendEmptyMessageDelayed(0,1000); } public static class MyHandler extends Handler{ private WeakReference<Activity> mActivity; public MyHandler(WeakReference<Activity> activityWeakReference){ mActivity = activityWeakReference; } @Override public void handleMessage(Message msg) { super.handleMessage(msg); if(null != mActivity){ Activity activity = mActivity.get(); if(null != activity && !activity.isFinishing()){ //TODO do something... } } } } }
4.2 内部调用Handler,解决办法,在Activity销毁的时候将Handler里面的信息清除。
public class MainActivity extends Activity { private Handler mHandler = new Handler(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mHandler.postDelayed(new Runnable() { @Override public void run() { } },1000); } @Override protected void onDestroy() { super.onDestroy(); mHandler.removeCallbacksAndMessages(null); } }
5. Thread引起的内存泄漏
下面的方法会产生内存泄漏,相信大概都知道,那么我们应该怎么去解决呢?public class MainActivity extends Activity { private Thread mThread; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mThread = new Thread(){ @Override public void run() { super.run(); while (true){ } } }; mThread.start(); } }
通过前面几种内存泄漏的解决方法,我相信大家应该也能猜出个大概,无非就是在Activity销毁的时候去暂停Thread那么我们应该怎么做呢?
@Override protected void onDestroy() { super.onDestroy(); if(null != mThread){ mThread.interrupt(); } }
interrupt()和Thread.interrupt()的区别,其中interrupt()是作用于调用线程的,比如我们上面调用的,他是作用于mThread这个线程的,如果我们在上面使用Thread.interrupt()那么就是作用于主线程的。
6. WebView造成的内存泄漏
WebView在解析网页时,会申请Native堆内存,保存页面元素(图片、history等)7. 其他原因
BraodcastReceiverContentObserver
File
Cursor
Stream
Bitmap
Timer
总结
上面是我在平时开发中遇到的一些关于内存泄漏的地方,大家有什么其他的内存泄漏或者对于以上有更好的解决方法,欢迎留言。后面会再写一篇关于内存泄漏的检测的文章。相关文章推荐
- android中常见的内存泄漏和解决的方法
- Android开发常见问题及解决方法
- android中httpclient和HttpURLConnection优缺点和常见bug解决方法
- androidpn-client 常见BUG解决方法
- Android开发常见问题及解决方法
- androidpn-client 常见BUG解决方法
- [Android开发常见问题-11] Unable to execute dex: Multiple dex files define 解决方法
- 内存泄漏以及常见的解决方法
- [Android环境搭建错误解决三]Android4.0.4源码编译常见错误及解决方法
- 内存泄漏常见情况及解决方法
- < Android 4.3 源代码下载 > Android repo sync 源代码附常见问题解决方法
- eclipse +android常见错误及解决方法
- [Android开发常见问题-11] Unable to execute dex: Multiple dex files define 解决方法
- android学习——android 常见的错误 和 解决方法
- android ListView常见问题解决方法(滚动背景变黑,去除滑动时阴影,拖动时Item图片不显示)
- 内存泄漏以及常见的解决方法
- 内存泄漏以及常见的解决方法
- [androidpn客户端] androidpn-client 常见BUG解决方法
- android学习——android 常见的错误 和 解决方法
- Android开发环境搭建和常见问题的解决方法