Android中的WeakReference弱引用的正确理解
如果一个对象只具有弱引用(就是说弱引用指向了某个对象,但只要该对象不是强引用或没有被强引用指向),那么在垃圾回收器线程扫描的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。不过,由于垃圾回收器是一个优先级很低的线程,因此不一定会很快发现那些只具有弱引用的对象。弱引用也可以和一个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被垃圾回收,Ja
如果一个对象只具有弱引用(就是说弱引用指向了某个对象,但只要该对象不是强引用或没有被强引用指向),那么在垃圾回收器线程扫描的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。不过,由于垃圾回收器是一个优先级很低的线程,因此不一定会很快发现那些只具有弱引用的对象。弱引用也可以和一个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被垃圾回收,Java虚拟机就会把这个弱引用加入到与之关联的引用队列中。
简单解释(以Activity为例)
在Activity中使用WeakReference<Activity>弱引用,Activity没有退出的情况下(在执行生命周期onDestroy()之前),弱引用对象WeakReference<Activity>被强引用Activity指向,该对象不会被GC检查时回收掉;在Activity退出的情况下(在执行生命周期onDestroy()之后),弱引用对象WeakReference<Activity>没有被强引用Activity指向,该对象就会被GC检查时回收掉。
什么是内存泄漏?
Java使用有向图机制,通过GC自动检查内存中的对象;如果GC发现一个或一组对象为不可达的状态,则将该对象从内存中回收。也就是说:一个对象不被任何引用所指向,则该对象会在被GC发现的时候回收。
可能导致内存泄漏的实例:
Handler造成的内存泄漏
Handler的使用造成的内存泄漏问题应该说最为常见了,平时在处理网络任务或者封装一些请求回调等api都应该会借助Handler来处理,对于Handler的使用代码编写一不规范即有可能造成内存泄漏,如下示例:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
requestData();
}
private void requestData(){
//在子线程中请求数据(就不写了),然后把数据发送到UI线程
Message message = Message.obtain();
mHandler.sendMessage(message);
}
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
//...
}
};
}
当使用内部类(或者匿名类)来创建Handler的时候,Handler对象会隐式地持有一个外部类的对象(通常是Activity)的引用(否则怎么可能通过Handler来操作Activity的View?)。而Handler通常会伴随着一个耗时的后台线程(比如:拉取网络图片);该后台线程在任务执行完毕后,通过消息机制通知Handler,然后Handler把图片更新到界面上。假设用户在网络请求过程中关闭了Activity,正常情况下这个Activity不再被使用,就有可能被GC回收;但此时线程尚未执行完毕,而该线程持有Handler的引用(不然怎么发送消息给Handler?),Handler又持有Activity的引用,就导致该Activity无法被回收(内存泄漏),直到网络请求结束(如:图片下载完毕)。另外如果执行了Handler的postDelayed(),该方法会将Handler装入一个Message,并把该Message推到MessageQueue中,由此产生了一条链式结构:MessageQueue->Message->Handler->Activity,导致Activity被持有引用而无法被回收(总结:实例对象Activity被其他对象Handler持有引用,而无法被回收)。
内存泄漏的危害是什么?
内存泄漏会引发虚拟机占用内存过高。对于Android应用程序来说,用户打开一个Activity,使用完之后关闭,内存泄漏;执行上述步骤多次,程序占用内存超过系统限制。
如何避免内存泄漏?可以使用什么方法?
由此引出了弱引用。用于非必需对象,被弱引用关联的对象只能生存到下一次GC发生之前。当GC工作时,无论当前内存是否足够,都会回收掉只被弱引用关联的对象(就是说弱引用指向了某个对象,但只要该对象不是强引用或没有被强引用指向)。
Handler内存泄漏问题解决(1.静态的内部类。2.使用弱引用。3.MainActivity退出的时候,移除消息队列中所有消息和所有的Runnable。)
public class MainActivity extends AppCompatActivity {
private MineHandler mHandler = new MineHandler(this);
private TextView mTextView ;
//1.静态的内部类
private static class MineHandler extends Handler {
//2.使用弱引用
private WeakReference<MainActivity> reference;
public MineHandler(MainActivity activity) {
reference = new WeakReference<MainActivity>(activity);
}
@Override
public void handleMessage(Message msg) {
MainActivity activity = (MainActivity) reference.get();
if(activity != null){
activity.mTextView.setText("");
}
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTextView = (TextView)findViewById(R.id.textview);
requestData();
}
private void requestData() {
//在子线程中请求数据(就不写了),然后把数据发送到UI线程
Message message = Message.obtain();
mHandler.sendMessage(message);
}
@Override
protected void onDestroy() {
//3.MainActivity退出的时候,移除消息队列中所有消息和所有的Runnable。
mHandler.removeCallbacksAndMessages(null);
super.onDestroy();
}
}
使用了上述代码后,在Activity退出的情况下(在执行生命周期onDestroy()之后),就算后台线程还没有结束,但由于仅有一个来自Handler的弱引用指向MainActivity,GC就会在检查的时候把WeakReference<MainActivity>回收掉。
另外,关于内存泄漏问题,可以参考博客Android内存泄漏详解和总结_ErwinNakajima的博客-CSDN博客,关于强引用、软引用、弱引用和虚引用的使用和正确理解,可以参考博客Android 强引用、软引用、弱引用和虚引用的使用和正确理解_ErwinNakajima的博客-CSDN博客_android 强软弱虚。
如对此有疑问,请联系qq1164688204。
推荐Android开源项目
项目功能介绍:RxJava2和Retrofit2项目,添加自动管理token功能,添加RxJava2生命周期管理,使用App架构设计是MVP模式和MVVM模式,同时使用组件化,部分代码使用Kotlin,此项目持续维护中。
项目地址:https://gitee.com/urasaki/RxJava2AndRetrofit2
更多推荐
所有评论(0)