java中引用分为四种强度:强引用,软引用、弱引用、虚引用
强引用:就是像Object obj = new Object()这种引用;
强引用存在时,垃圾回收器不会回收。
1、软引用:SoftReference类来实现
只有当内存快要溢出时才会回收这部分内存,经常应用在缓存技术中。
可以关联一个引用队列,当出现溢出时JVM回收这部分内存后,会将这个引用放入这个关联的引用队列。
// 软引用
public static void test() {
SoftReference<String> sr = new SoftReference<String>(new String("hello"));
System.out.println(sr.get());
System.gc();
System.out.println(sr.get());
}
运行结果如下
hello
hello
内存并很充足,所以不会回收
2、弱引用:WeakReference类来实现
描述非必须对象。强度比软引用更弱。被弱引用关联的对象只能生存到下一次垃圾回收器工作之前。垃圾回收器开始工作时,无论是否内存充足都会回收。
可以关联一个引用队列,当该引用对象被JVM回收时,会将该引用放入该队列中。
// 弱引用
public static void test2() {
WeakReference<String> sr = new WeakReference<String>(new String("hello"));
System.out.println(sr.get());
System.gc(); //通知JVM的gc进行垃圾回收
System.out.println(sr.get());
}
运行结果
hello
null
gc运行时就会将内存收回
3、虚引用:PhantomReference类来实现
最弱的引用关系。这个引用存在不存在不影响其对象的生存,唯一的目的就是能在这个对象被垃圾回收器回收时收到一个系统通知。(就是放入引用队列中)
如果一个对象与虚引用关联,则跟没有引用与之关联一样,在任何时候都可能被垃圾回收器回收。而且不能通过虚引用访问到对象值。
// 虚引用
public static void test3() throws InterruptedException {
String str = new String("hello");
ReferenceQueue<String> queue = new ReferenceQueue<String>();
System.out.println("queue:"+queue.poll());
// 建立一个虚引用,关联一个引用队列
PhantomReference<String> pr = new PhantomReference<String>(str, queue);
System.out.println("queue:"+queue.poll());
System.out.println("pr:"+pr.get());
str = null;
// 启动垃圾回收器
System.gc();
Thread.sleep(2000);// 个垃圾回收器运行时间
System.out.println(queue.poll());
}
运行结果
queue:null
queue:null
pr:null
java.lang.ref.PhantomReference@15db9742
JVM回收了这部分内存,然后将虚引用放入引用队列。注意这些被回收的引用仅仅只是一个引用,引用值为null
应用
软引用适合用来进行缓存,当内存不够时能让JVM回收内存;
弱引用能用来在回调函数中防止内存泄露。因为回调函数往往是匿名内部类,隐式保存有对外部类的引用,所以如果回调函数是在另一个线程里面被回调,而这时如果需要回收外部类,那么就会内存泄露,因为匿名内部类保存有对外部类的强引用。