JAVA 的四种引用方式

我们知道java语言提供了4种引用类型:强引用、软引(SoftReference)、弱引用(WeakReference)和幽灵引用(PhantomReference),与引用密切相关的,还有一个引用队列ReferenceQueue。引用和引用队列的关系,对于垃圾回收来说非常重要,学习垃圾回收机制,必须要先了解引用和引用队列的使用方法。本文主要参考网上的一些理论,同时配合自己的一些测试代码,更好的理解这些概念。这篇博客也解决了 System.gc()和-XX:+DisableExplicitGC启动参数,以及DirectByteBuffer的内存释放 中遗留的幽灵引用的问题。
1、强引用
强引用不会被GC回收,并且在java.lang.ref里也没有实际的对应类型,平时工作接触的最多的就是强引用。
  Object obj = new Object();这里的obj引用便是一个强引用。如果一个对象具有强引用,那就类似于必不可少的生活用品,垃圾回收器绝不会回收它。当内存空 间不足,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足问题。
2、软引用
如果一个对象只具有软引用,那就类似于可有可无的生活用品。如果内存空间足够,垃圾回收器就不会回收它,如果内存空间不足了,就会回收这些对象的内存。只 要垃圾回收器没有回收它,该对象就可以被程序使用。软引用可用来实现内存敏感的高速缓存。 软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被垃圾回收,Java虚拟机就会把这个软引用加入到与之关联的引用队列中。
/* 只有当内存不够的时候,才回收这类内存,因此在内存足够的时候,它们通常不被回收 * *

public class Test {
    public static void main(String[] args) throws Exception { 
         Object obj = new Object(); 
         ReferenceQueue refQueue = new ReferenceQueue(); 
         SoftReference softRef = new SoftReference(obj, refQueue); 
         System.out.println(softRef.get()); 
         System.out.println(refQueue.poll());
         // null // 清除强引用,触发GC 
         obj = null; 
         System.gc();
         System.out.println(softRef.get()); 
         Thread.sleep(200); 
         System.out.println(refQueue.poll()); 
         }

1、System.gc()告诉JVM这是一个执行GC的好时机,但具体执不执行由JVM决定(事实上这段代码一般都会执行GC)
2、Thread.sleep(200); 这是因为从对象被回收到JVM将引用加入refQueue队列,需要一定的时间。而且poll并不是一个阻塞方法,如果没有数据会返回null,所以我们选择等待一段时间。

3.弱引用
弱引用也是用来描述非必需对象的,当JVM进行垃圾回收时,无论内存是否充足,都会回收被弱引用关联的对象。在java中,用java.lang.ref.WeakReference类来表示。下面是使用示例:

public class test {  
    public static void main(String[] args) {  
        WeakReference<People>reference=new WeakReference<People>(new People("zhouqian",20));  
        System.out.println(reference.get());  
        System.gc();//通知GVM回收资源  
        System.out.println(reference.get());  
    }  
}  
class People{  
    public String name;  
    public int age;  
    public People(String name,int age) {  
        this.name=name;  
        this.age=age;  
    }  
    @Override  
    public String toString() {  
        return "[name:"+name+",age:"+age+"]";  
    }  
}  

[name:zhouqian,age:20]
null
第二个输出结果是null,这说明只要JVM进行垃圾回收,被弱引用关联的对象必定会被回收掉。不过要注意的是,这里所说的被弱引用关联的对象是指只有弱引用与之关联,如果存在强引用同时与之关联,则进行垃圾回收时也不会回收该对象(软引用也是如此)

public class test {  
    public static void main(String[] args) {  
        People people=new People("zhouqian",20);  
        WeakReference<People>reference=new WeakReference<People>(people);//<span style="color:#FF0000;">关联强引用</span>  
        System.out.println(reference.get());  
        System.gc();  
        System.out.println(reference.get());  
    }  
}  
class People{  
    public String name;  
    public int age;  
    public People(String name,int age) {  
        this.name=name;  
        this.age=age;  
    }  
    @Override  
    public String toString() {  
        return "[name:"+name+",age:"+age+"]";  
    }  
}//结果发生了很大的变化  
[name:zhouqian,age:20]  
[name:zhouqian,age:20]  

弱引用可以和一个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被JVM回收,这个软引用就会被加入到与之关联的引用队列中。
4.虚引用
 虚引用和前面的软引用、弱引用不同,它并不影响对象的生命周期。在java中用java.lang.ref.PhantomReference类表示。如果一个对象与虚引用关联,则跟没有引用与之关联一样,在任何时候都可能被垃圾回收器回收。
  要注意的是,虚引用必须和引用队列关联使用,当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会把这个虚引用加入到与之 关联的引用队列中。程序可以通过判断引用队列中是否已经加入了虚引用,来了解被引用的对象是否将要被垃圾回收。如果程序发现某个虚引用已经被加入到引用队列,那么就可以在所引用的对象的内存被回收之前采取必要的行动。
  

public class Main {  
    public static void main(String[] args) {  
        ReferenceQueue<String> queue = new ReferenceQueue<String>();  
        PhantomReference<String> pr = new PhantomReference<String>(new String("hello"), queue);  
        System.out.println(pr.get());  
    }  
}  

5.软引用和弱引用
对于强引用,我们平时在编写代码时经常会用到。而对于其他三种类型的引用,使用得最多的就是软引用和弱引用,这2种既有相似之处又有区别。它们都是用来描述非必需对象的,但是被软引用关联的对象只有在内存不足时才会被回收,而被弱引用关联的对象在JVM进行垃圾回收时总会被回收。
在SoftReference类中,有三个方法,两个构造方法和一个get方法(WekReference类似):
两个构造方法:

public SoftReference(T referent) {  
    super(referent);  
    this.timestamp = clock;  
    }  
public SoftReference(T referent, ReferenceQueue<? super T> q) {  
    super(referent, q);  
    this.timestamp = clock;  
    }  

猜你喜欢

转载自blog.csdn.net/s_yj_q/article/details/79938755