背景
在java中,存在4种引用关系,但是4种引用关系也有一些差异,这里主要讨论若引用和虚引用,但是一些细节点讨论:
- API上有什么不同 ?
- 虚引用和弱引用有什么不同?如果都是GC时都被回收,为什么不使用虚引用呢 ?
- 引用实例的强引用释放之后,有什么不同?
解答:
- 但是在gc上,他们很类似,但有有些区别,java 8.0之前,虚引用持有对象可能无法释放,因为为了通知对象将要被回收,虚引用会标记对象是激活状态,导致无法回收,java 8之后几乎完全一样,虚引用通知对象被回收在虚引用回收之后。
- 产生时期不同
那么既然 java 8之后虚引用会被回收,为什么不使用虚引用而使用弱引用呢 ?
主要原因是虚引用的api决定了,get() 返回值是null
使用注意事项
常量:
不要使用虚引用引用常量 (基本类型+字面量字符串),因为常量的生命周期相对较长
静态成员:
不要引用静态成员,Class,因为这类成员生命周期也是很长
局部变量:
不要引用局部变量,局部变量引用如果是异步+callback方式,很容易因为内存问题,导致局部变量提前被释放,造成不可控风险。
public static void main(String[] args){
final Logger log = new Logger("HaHaha");
testHttp(new WeakReference(log))
}
public void testHttp(WeakReference<Logger> ref){
okHttpClient.newCall(request).enqueue(new Callback() {
@Override public void onFailure(Call call, IOException e) {
e.printStackTrace();
Logger log = ref.get(); //log可能提前为空
}
@Override public void onResponse(Call call, Response response) throws IOException {
try (ResponseBody responseBody = response.body()) {
Logger log = ref.get(); //log可能提前为空
if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
Headers responseHeaders = response.headers();
for (int i = 0, size = responseHeaders.size(); i < size; i++) {
System.out.println(responseHeaders.name(i) + ": " + responseHeaders.value(i));
}
System.out.println(responseBody.string());
}
}
});
}
}