一、JAVA的四种引用类型
1.强引用
Object obj = new Object();
String str = "Hello";
这类通常的实例化对象
2.弱引用
WeakReference 当JVM进行垃圾回收时无论内存是否充足,都会回收被弱引用关联的对象。可用于解决内存泄漏
3.软引用
SoftReference 只有当JVM内存不足时才会回收软引用关联的对象
4.虚引用
PhantomReference 不影响对象的被垃圾回收的时机
ReferenceQueue<String> queue = new ReferenceQueue<String>();
PhantomReference<String> pr = new PhantomReference<String>("Hello" queue);
虚引用必须和引用队列关联使用,当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会把这个虚引用加入到与之 关联的引用队列中。程序可以通过判断引用队列中是否已经加入了虚引用,来了解被引用的对象是否将要被垃圾回收。
二、Handler导致的内存泄漏
非静态的Handler内部类,默认会持有外部的Activity引用。
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_detail);
handler = new Handler(){
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
}
};
Message message = handler.obtainMessage(1);
message.obj = "Hello";
handler.sendMessageDelayed(message, 40000);
}
Handler#sendMessageDelayed 方法,会调用Handler.mQueen.enqueueMessage(Message msg, long when)
将Message 加入 MesssageQueen ,并设置设置message.target = this(Handler对象)
上诉流程会形成 如下依赖链
Message -> MessageQueen -> Handler -> Activity
MesageQueen->MainLooper(和application生命周期一致)
Message 和 MessageQueen 的依赖 Message 被发送时才会解除
Activity退出后,在Delay时间到达之前,无论发生多少次GC,根据可达性分析,Activity的内存都不应该被释放。
解决方案
- 切断Message到Queen 到引用链,即在Activity销毁时调用 handler.removeMessages(1)
- 将Handler到Activity的引用变为弱应用,即改用静态的Handler子类,传入WeakReference的Activity应用:
public static class DetailHandler extends Handler {
private WeakReference<DetailActivity> contextWeakReference;
public DetailHandler(DetailActivity context) {
this.contextWeakReference = new WeakReference<>(context);
}
public DetailActivity getContextWeakReference() {
return contextWeakReference.get();
}
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
}
}
3.静态的实例持有非静态的类(短周期的对象)
public class AppManager {
private static AppManager INSTANCE;
private Context context;
private AppManager(Context context) {
this.context = context;
}
public static AppManager getInstance(Context context) {
return new AppManager(context);
}
public void test(){
}
}
INSTANCE 的生命周期和整个App一致,如果getInstance 传入的Context 为Activty,则Activty会被AppManager一直持有,导致Activity在gc时不能被释放。
解决方案
这里传入ApplicationContext这样的长周期对象即可。
其他类型的引用可以根据实际情况,在适当的时机置空即可。
网友评论