Java四种引用类型及垃圾回收

强引用

强引用是我们接触最多的引用,若果是强引用JVM宁愿抛出OOM也不愿回收具有强引用的对象。

软引用

具有软引用的对象,内存空间充足的时候,垃圾回收器不会回收,当内存空间不充足的时候,垃圾回收器回收。

 

public class SoftReferenceTest {
    public static void main(String[] args) {
        String string = new String("hello world");
        SoftReference<String> reference = new SoftReference<String>(string);
        string = null;
        System.out.println("gc()前弱引用所指向的对象是: "+reference.get());
        System.gc();//gc()不一定立刻执行垃圾回收
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("gc()后弱引用所指向的对象是: "+reference.get());
    }
}
//结果(因为内存充足所以没有被回收)
gc()前弱引用所指向的对象是: hello world
gc()后弱引用所指向的对象是: hello world

弱引用

在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。

 

public class WeakReferenceTest {
    public static void main(String[] args) {
        String string = new String("hello world");
        WeakReference<String> reference = new WeakReference<String>(string);
        string = null;
        System.out.println("gc()前弱引用所指向的对象是: " + reference.get());
        System.gc();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("gc()后弱引用所指向的对象是: " + reference.get());
    }
}
//结果
gc()前弱引用所指向的对象是: hello world
gc()后弱引用所指向的对象是: null

String string = "hello world";//常量池不能被回收
WeakReference<String> reference = new WeakReference<String>(string);
string = null;
System.out.println("gc()前弱引用所指向的对象是: " + reference.get());
System.gc();
try {
    Thread.sleep(1000);
} catch (InterruptedException e) {
    e.printStackTrace();
}
System.out.println("gc()后弱引用所指向的对象是: " + reference.get());

//结果
gc()前弱引用所指向的对象是: hello world
gc()后弱引用所指向的对象是: hello world

虚引用

虚引用主要用来跟踪对象被垃圾回收器回收的活动。虚引用与软引用和弱引用的一个区别在于:虚引用必须和引用队列 (ReferenceQueue)联合使用。当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之关联的引用队列中。

 

public class PhantomReferenceTest {
    public static void main(String[] args) {
        String string = new String("hello world");
        //必须和引用队列一起使用
        PhantomReference<String> reference = new PhantomReference<String>(string,new ReferenceQueue<String>());
        string = null;
        System.out.println("gc()前虚引用所指向的对象是: " + reference.get());
        System.gc();//gc()不一定立刻执行垃圾回收
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("gc()后虚引用所指向的对象是: " + reference.get());
    }
}
//结果
gc()前虚引用所指向的对象是: null
gc()后虚引用所指向的对象是: null

一个永远返回 null的reference 要来何用,请注意构造PhantomReference时的第二个参数 ReferenceQueue(事实上WeakReference & SoftReference 也可以有这个参数),PhantomReference唯一的用处就是跟踪referent何时被 enqueue到ReferenceQueue中。

引用队列

软引用、弱引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被垃圾回收器回收,Java虚拟机就会把这个软引用加入到与之关联的引用队列中。

 

//软引用和引用队列
public class ReferenceQueueTest {
    public static void main(String[] args) throws InterruptedException {
        Object referent = new Object();
        ReferenceQueue<Object> referenceQueue = new ReferenceQueue<Object>();
        SoftReference<Object> weakReference = new SoftReference<Object>(referent, referenceQueue);

        System.out.println("垃圾回收器或程序是否添加该引用到引用队列:   " + weakReference.isEnqueued());
        Reference<? extends Object> polled = referenceQueue.poll();
        System.out.println("返回队列可用的对象: " + polled);
        referent = null;
        System.gc();
        Thread.sleep(1000);
        //weakReference.enqueue();//取消注释则运行结果和弱引用一样
        System.out.println("垃圾回收器及程序是否添加该引用到引用队列:   " + weakReference.isEnqueued());

        Reference<? extends Object> removed = referenceQueue.remove();
        System.out.println("阻塞移除队列的中的引用对象:   " + removed);
    }
}
//结果(阻塞)
垃圾回收器或程序是否添加该引用到引用队列:   false
返回队列可用的对象: null
垃圾回收器及程序是否添加该引用到引用队列:   false

//弱引用和引用队列
public class WeakReferenceTest {
    public static void main(String[] args) throws InterruptedException {
        Object referent = new Object();
        ReferenceQueue<Object> referenceQueue = new ReferenceQueue<Object>();
        WeakReference<Object> weakReference = new WeakReference<Object>(referent, referenceQueue);

        System.out.println("垃圾回收器或程序是否添加该引用到引用队列    :   " + weakReference.isEnqueued());
        Reference<? extends Object> polled = referenceQueue.poll();
        System.out.println("返回队列可用的对象   : " + polled);
        referent = null;
        System.gc();
        Thread.sleep(1000);
        System.out.println("垃圾回收器及程序是否添加该引用到引用队列    :   " + weakReference.isEnqueued());

        Reference<? extends Object> removed = referenceQueue.remove();
        System.out.println("阻塞移除队列的中的引用对象   :   " + removed);
    }
}
//结果
垃圾回收器或程序是否添加该引用到引用队列    :   false
返回队列可用的对象   : null
垃圾回收器及程序是否添加该引用到引用队列    :   true
阻塞移除队列的中的引用对象   :   java.lang.ref.WeakReference@511d50c0

再谈虚引用

(1)用来实现比较精细的内存使用控制

private byte[] data = new byte[0];
private ReferenceQueue<byte[]> queue = new ReferenceQueue<byte[]>();
private PhantomReference<byte[]> ref = new PhantomReference<byte[]>(data, queue);
public byte[] get(int size) {
    if (size <= 0) {
        throw new IllegalArgumentException("Wrong buffer size");
    }
    if (data.length < size) {
        data = null;
        System.gc(); //强制运行垃圾回收器
        try {
            queue.remove(); //该方法会阻塞直到队列非空
            ref.clear(); //幽灵引用不会自动清空,要手动运行
            ref = null;
            data = new byte[size];
            ref = new PhantomReference<byte[]>(data, queue);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    return data;
}

再谈弱引用

WeakHashMap 使用 WeakReference 作为 key, 一旦没有指向 key 的强引用, WeakHashMap 在 GC 后将自动删除相关的 entry。(ThreadLocal中有WeakHashMap的使用,大家可以看看ThreadLocal的源码

Map<Object, Object> weakHashMap = new WeakHashMap<Object, Object>();
Object key = new Object();
Object value = new Object();
weakHashMap.put(key, value);
System.out.println(weakHashMap.containsValue(value));

key = null;
System.gc();
Thread.sleep(1000);


//一旦没有指向 key 的强引用, WeakHashMap 在 GC 后将自动删除相关的 entry

System.out.println(weakHashMap.containsValue(value));

//结果
true
false

再谈软引用

一个对象具有软引用,当内存充足的时候垃圾回收器不会回收该对象,当内存不足的时候对象会被回收。这个特点所以软引用用来实现内存敏感的高速缓存。使用软引用能防止内存泄露,增强程序的健壮性。 

参考:

http://www.iteye.com/topic/401478

http://www.infoq.com/cn/articles/cf-java-garbage-references

转载于:https://my.oschina.net/u/2361475/blog/603125

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值