java中的weakReference-弱引用
1.介绍
阅读ThreadLocal源码中,其中嵌套类ThreadLocalMap中的Entry继承了WeakReferenc,为了能搞明白ThreadLocal,需要对类WeakReference进一步认识。WeakReference如字面意思,弱引用, 当一个对象仅仅被weak reference(弱引用)指向, 而没有任何其他strong reference(强引用)指向的时候, 如果这时GC运行, 那么这个对象就会被回收,不论当前的内存空间是否足够,这个对象都会被回收。
2.类WeakReference源码
public class WeakReference<T> extends Reference<T> {
/**
* Creates a new weak reference that refers to the given object. The new
* reference is not registered with any queue.
*
* @param referent object the new weak reference will refer to
*/
public WeakReference(T referent) {
super(referent);
}
/**
* Creates a new weak reference that refers to the given object and is
* registered with the given queue.
*
* @param referent object the new weak reference will refer to
* @param q the queue with which the reference is to be registered,
* or <tt>null</tt> if registration is not required
*/
public WeakReference(T referent, ReferenceQueue<? super T> q) {
super(referent, q);
}
}
-
WeakReference(T referent):referent就是被弱引用的对象。
-
WeakReference(T referent, ReferenceQueue<? super T> q):referent就是被弱引用的对象,ReferenceQueue队列,当对象referent被系统GC回收时,对象本身(继承WeakReference的对象或WeakReference对象)自动加入ReferenceQueue队列当中。
-
注意:弱引用对象是WeakReference(referentObject) 中的 referentObject 对象,并不是继承WeakReference的子类。
3.例子
3.1 WeakReference 示例1
java类:Computer
/**
* @author
*/
public class Computer {
private String name;
public Computer(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
/**
* 覆盖finalize,在对象被GC回收的时候会自动执行。
* @throws Throwable
*/
@Override
protected void finalize() throws Throwable {
super.finalize();
System.out.println("Computer GC: " + name + " finalize!");
}
@Override
public String toString() {
return "Computer{" +
"name='" + name + '\'' +
'}';
}
}
java类:Product
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
/**
* 产品
* 注意:弱引用对象是传入泛型T,不是类Product
* @author
*/
public class Product<T> extends WeakReference {
public Product(T referent) {
super(referent);
}
public Product(Object referent, ReferenceQueue q) {
super(referent, q);
}
}
Main.test1()方法
public class Main {
public static void main(String[] args) {
test1();
}
public static void test1() {
Product product = new Product(new Computer("dell"));
System.out.println(product);
System.out.println(product.get());
System.out.println("gc之前");
// 执行gc,内存回收
System.gc();
// 睡眠1s,等待系统回收内存
try {
System.out.println("等待1s...");
Thread.sleep(1000L);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("gc之后");
System.out.println(product);
System.out.println(product.get());
}
}
执行输出
# product引用对象
test1.Product@1b6d3586
# product.computer弱引用对象输出
Computer{name='dell'}
gc之前
等待1s...
# computer对象自动回收方法回调
Computer GC: dell finalize!
gc之后
# product引用对象
test1.Product@1b6d3586
# product.computer弱引用对象输出
null
结论:
- 弱引用对象是WeakReference(referentObject) 中的 referentObject 对象。
- JVM,自动GC或者是手动GC, 不论当前的内存空间是否足够,弱引用对象都会被回收。
- 其他,弱引用对象在使用时要严谨,可能会造成内存泄漏,造成内存浪费;ThreadLocal会造成内存泄漏。
3.2 WeakReference 示例2
ReferenceQueue的使用
public class Main {
public static void main(String[] args) {
test2();
}
public static void test2() {
ReferenceQueue<Computer> referenceQueue = new ReferenceQueue<>();
WeakReference<Computer> weakReference1 = new WeakReference<Computer>(new Computer("Dell"), referenceQueue);
WeakReference<Computer> weakReference2 = new WeakReference<Computer>(new Computer("Apple"), referenceQueue);
System.out.println("=====gc调用前=====");
Reference<? extends Computer> reference1 = null;
while ((reference1 = referenceQueue.poll()) != null) {
System.out.println(reference1);
}
System.out.println(weakReference1);
System.out.println(weakReference2);
System.out.println(weakReference1.get());
System.out.println(weakReference2.get());
System.out.println("=====调用gc=====");
System.gc();
try {
Thread.sleep(1000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("=====gc调用后=====");
//下面两个输出为null,表示对象被回收了
System.out.println(weakReference1.get());
System.out.println(weakReference2.get());
//输出结果,并且就是上面的appleWeakReference、appleWeakReference2,再次证明对象被回收了
Reference<? extends Computer> reference2 = null;
while ((reference2 = referenceQueue.poll()) != null) {
//如果使用继承的方式就可以包含其他信息了
System.out.println("referenceQueue:" + reference2);
}
}
输出
=====gc调用前=====
java.lang.ref.WeakReference@39a054a5
java.lang.ref.WeakReference@71bc1ae4
Computer{name='Dell'}
Computer{name='Apple'}
=====调用gc=====
Computer GC: Apple finalize!
Computer GC: Dell finalize!
=====gc调用后=====
null
null
referenceQueue:java.lang.ref.WeakReference@39a054a5
referenceQueue:java.lang.ref.WeakReference@71bc1ae4
结论:
- ReferenceQueue队列,当对象referent被系统GC回收时,继承WeakReference的对象或WeakReference对象自动加入ReferenceQueue队列当中。