小白日记[强引用 软引用 弱引用 虚引用]

小白一枚,请多指教

小白今日任务:了解Java中的四种引用

1、强应用

强应用是Java中普遍性的引用,覆盖我们编码中大部分场景,比如new出的一个普通对象都属于强引用,作为普通的程序员可能编程生涯基本就跟强引用打交道,下面是一个强引用的例子:

    @Test
    public void referenceDemo() {
        Object o = new Object();
        System.out.println("before gc is "+ o);
        // 手动调起GC
        System.gc();
        System.out.println("after gc is "+ o);
        try {
            // 手动调节堆内存,让程序OOM异常  -Xms10m -Xmx10m
            byte[] bytes = new byte[11 * 1024 * 1024];
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            System.out.println("after oom is "+ o);
        }
    }

运行得到结果(程序中模拟了GC和OOM异常情况下的引用情况)

before gc is java.lang.Object@382db087
after gc is java.lang.Object@382db087
after oom is java.lang.Object@382db087
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space

可以发现在强引用下,GC不会回收强引用,JVM即使发生OutOfMemoryError也不会试图回收强引用对象来腾出空间

2、软应用

软引用较强引用弱一级,在JVM在内存不足时会试图回收软引用的对象来解决内存不足,软引用的应用场景,可以参考软引用的Java源码注释:

/**
 * Soft reference objects, which are cleared at the discretion of the garbage
 * collector in response to memory demand.  Soft references are most often used
 * to implement memory-sensitive caches.
 *

可以看到软引用一般用于实现内存敏感的缓存中( most often used to implement memory-sensitive caches.),因为缓存的应用场景为:缓存常用数据,加速数据操作,但是在内存不足时可消减,正好符合软引用的定位,下面是软引用的例子:

    @Test
    public void softReferenceDemo() {
        Object o = new Object();
        SoftReference<Object> softReference = new SoftReference<>(o);
        // 解除强引用,目前只有一个软引用对象
        o = null;
        System.out.println("before gc is "+ softReference.get());
        // 手动调起GC
        System.gc();
        System.out.println("after gc is "+ softReference.get());
        try {
            // 手动调节堆内存,让程序OOM异常  -Xms10m -Xmx10m
            byte[] bytes = new byte[11 * 1024 * 1024];
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            System.out.println("after oom is "+ softReference.get());
        }
    }

运行得到结果(程序中模拟了GC和OOM异常情况下的引用情况)

before gc is java.lang.Object@382db087
after gc is java.lang.Object@382db087
after oom is null
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space

可以发现在软引用下,内存正常时,GC不会回收软引用对象,但是OutOfMemoryError时回收了对象用来解决内存不足

3、弱应用

弱引用较软引用弱一级,GC时只要扫描到弱引用就会回收释放空间,应用场景与软引用类似,可以参考源码中的注释:

/**
 * Weak reference objects, which do not prevent their referents from being
 * made finalizable, finalized, and then reclaimed.  Weak references are most
 * often used to implement canonicalizing mappings.
 *

可以看到弱引用一般用于实现一些规范化的映射关系(often used to implement canonicalizing mappings.),也就是缓存场景,下面时弱引用的例子:

    @Test
    public void weakReference() {
        Object o = new Object();
        WeakReference<Object> weakReference = new WeakReference<>(o);
        // 解除强引用,目前只有一个弱引用对象
        o = null;
        System.out.println("before gc is "+ weakReference.get());
        // 手动调起GC
        System.gc();
        System.out.println("after gc is "+ weakReference.get());
    }

运行得到结果(程序中模拟了GC下的引用情况)

before gc is java.lang.Object@382db087
after gc is null

可以发现在弱引用下,即使内存正常,GC也会回收掉弱引用对象

上面说到"规范化的映射关系"也就引申出了 WeakHashMap,用法与HashMap基本一致,GC时会释放,是一般缓存的具体底层实现

4、虚应用

与其他引用不同,虚引用的存在不是为了存储,因为如它的名字一样他几乎在JVM中形同虚设,参照源码中的注释:

/**
 * Phantom reference objects, which are enqueued after the collector
 * determines that their referents may otherwise be reclaimed.  Phantom
 * references are most often used for scheduling pre-mortem cleanup actions in
 * a more flexible way than is possible with the Java finalization mechanism.

从源码注释中可以看到,虚引用会被回收到队列中,构造PhantomReference时也可以发现PhantomReference必须要一个队列参数,具体就是 ReferenceQueue,常用来安排一些回收前的清理操作(most often used for scheduling pre-mortem cleanup actions),实际中几乎用不到,但是可以作为一个知识扩展,下面可以通过一个例子演示:

    @Test
    public void phantomReference() {
        Object o = new Object();
        ReferenceQueue referenceQueue = new ReferenceQueue();
        PhantomReference<Object> phantomReference = 
                        new PhantomReference<>(o, referenceQueue);
        // 解除强引用,目前只有一个虚引用对象
        o = null;
        System.out.println("before gc phantomReference is "+ phantomReference.get());
        System.out.println("before gc referenceQueue is "+ referenceQueue.poll());
        // 手动调起GC
        System.gc();
        System.out.println("after gc phantomReference is "+ phantomReference.get());
        System.out.println("after gc referenceQueue is "+ referenceQueue.poll());
    }

运行得到结果(程序中模拟了GC下的引用情况)

before gc phantomReference is null
before gc referenceQueue is null
after gc phantomReference is null
after gc referenceQueue is java.lang.ref.PhantomReference@382db087

可以看出虚引用无论GC与否都处于“虚无状态”,并且在GC后会被放入ReferenceQueue队列中,可以通过操作ReferenceQueue队列灵活的进行一些清理工作

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值