关于 Android 内存泄漏的那些事
需要手动关闭的资源没有关闭如 IO 流需要调用 close()方法进行关闭,广播需要取消注册等,而且需要在 finally 块中执行,保证无论如何都会关闭。
Handler 使用不当错误代码
public class MainActivity extends AppCompatActivity {private Handler mHandler = new Handler(){@Overridepublic void handleMessage(Message msg) {//do something}};private void loadData(){//do requestMessage message = Message.obtain();mHandler.sendMessage(message);}@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);loadData();}}
这种情况 mHandler 是 Handler 的非静态匿名内部类的实例,持有外部类 Activity 的引用,如果这个 Activity 退出时消息队列中还有未处理的消息或者正在处理的消息,那么这时候 Message 持有 mHandler 实例的引用,mHandler 又持有 Activity 的引用,所以导致该 Activity 的内存资源无法及时回收,引发内
存泄漏。正确代码
public class MainActivity extends AppCompatActivity {private MyHandler mHandler = new MyHandler(this);private void loadData() {//do requestMessage message = Message.obtain();mHandler.sendMessage(message);}private static class MyHandler extends Handler {private WeakReference<Context> reference;public MyHandler(Context context) {reference = new WeakReference<Context>(context);}@Overridepublic void handleMessage(Message msg) {super.handleMessage(msg);MainActivity mainActivity = (MainActivity) reference.get();if (mainActivity != null) {//do something to update UI via mainActivity}}}@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);loadData();}}
创建一个静态 Handler 内部类,然后对 Handler 持有的对象使用弱引用。(弱引用,即在引用对象的同时仍然允许通过垃圾回收来回收该对象。)同时,对于还未处理完的消息,应在 onDestroy()中通过 removeCallbacksAndMessages(null)移除。
@Overrideprotected void onDestroy() {super.onDestroy();mHandler.removeCallbacksAndMessages(null);}
** AsyncTask 使用不当**AsyncTask 造成内存泄漏的情况和 Handler 一样,这里不多说,直接上代码。错误代码
public class MainActivity extends AppCompatActivity {
@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);new MyAscnyTask().execute();}
class MyAscnyTask extends AsyncTask<Void, Integer, String>{@Overrideprotected String doInBackground(Void... params) {try {Thread.sleep(5000);} catch (InterruptedException e) {e.printStackTrace();}return "";}}}
MyAsyncTask 是一个非静态内部类,在 doInbackground() 方法中执行耗时操作。如果在耗时操作结束之前,Activity 被销毁了,这时候因为 MyAsyncTask 持有 Activity 的强引用,便会导致 Activity 的内存无法被回收,产生内存泄露。**解决:**使用静态内部类+弱引用,类似 Handler 。线程引发的内存泄漏线程生命周期的不可控性导致很容易引发内存泄漏。一段经典的代码:错误代码
new Thread(new Runnable() {@Overridepublic void run() {try {Thread.sleep(50000);} catch (InterruptedException e) {e.printStackTrace();}}}).start();
new 出一个匿名的 Thread,进行耗时的操作,线程隐式持有 Activity 的引用,Thread 中的耗时操作没有结束时,Activity 也不会被销毁,导致内存泄漏。解决:使用静态内部类+弱引用。集合造成内存泄漏错误代码
static List<Object> objectList = new ArrayList<>();for (int i = 0; i < 10; i++) {Object obj = new Object();objectList.add(obj);obj = null;}
我们将一个对象添加到 List 等集合中,这个集合就会持有该对象的引用。这段代码中的 objectList 是静态变量,生命周期和 app 一致,它持有集合中对象的引用,导致这些对象无法被释放,造成内存泄漏。解决:
objectList.clear();objectList = null;
objectList.clear();将集合中的所有对象都释放了,但是 list 对象还是存在。**objectList = null;**将集合置空,为集合分配的空间也会回收。
WebView 造成内存泄漏
评论