强引用

Java中默认声明的就是强引用。
只要强引用存在,垃圾回收器将永远不会回收被引用的对象,哪怕内存不足时,JVM也会直接抛出OutOfMemoryError,不会去回收。如果想中断强引用与对象之间的联系,可以显示的将强引用赋值为null,这样一来,JVM就可以适时的回收对象了

public class O {

    //对象会回收会调用此方法
    //平时不要重写,会出现OOM问题
    @Override
    protected void finalize() throws Throwable {
        System.out.println("finalize");
    }
}

---------------------------

public class Test {
    public static void main(String[] args){
        O o = new O();  //强引用
        o = null;       //置空,new O()就是垃圾了,会被gc回收
        System.gc();    //通知虚拟机进行垃圾回收

    }
    
    /* 打印结果:
    finalize
     */
}

软引用

软引用是用来描述一些非必需但仍有用的对象。
在内存足够的时候,软引用对象不会被回收,只有在内存不足时,系统则会回收软引用对象,如果回收了软引用对象之后仍然没有足够的内存,才会抛出内存溢出异常。
可以用来存放一些大图片等缓存。

import java.lang.ref.SoftReference;

//测试例子前,先设置一些VM Options参数-Xmx20M,代表堆内存只有20M
public class Test {
    public static void main(String[] args){
        //软引用,即new SoftReference<byte[]>里面有软引用指向new byte[1024 * 1024 * 10]
        SoftReference<byte[]> m = new SoftReference<byte[]>(new byte[1024 * 1024 * 10]);

        //拿
//        byte[] b = m.get();
        System.out.println(m.get());   //没被回收

        //回收
        System.gc();
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(m.get());   //没被回收

        //再分配很大的数组,heap内存装不下,系统会自动进行回收,即软引用会被回收
        //超出定义的堆内存((10 + 10 = 20) > (20 - 额外的一些占用))
        byte[] other = new byte[1024 * 1024 * 10];
        System.out.println(m.get());   //被回收



    }

    /* 打印结果:
    [B@14ae5a5
    [B@14ae5a5
    null
     */
}

弱引用

ThreadLocal的set方法里面的Entry类就用到弱引用,防止内存泄漏。

ThreadLocal set时是Entry(key, value)set进ThreadLocalMap,而Entry是extends WeakReference<ThreadLocal<?>>的,所以当ThreadLocal=null时,GC会把ThreadLocal回收,但是Thread不死,ThreadLocalMap就会一直存在 ,GC把ThreadLocal回收后,ThreadLocalMap还存在一条无用的信息(key没了,value还在),这样就造成了内存泄漏,所以在ThreadLocal使用完成后,请调用remove方法。

import java.lang.ref.WeakReference;
public class Test {
    public static void main(String[] args){
        WeakReference<byte[]> m = new WeakReference<>(new byte[10]);
        System.out.println(m.get());
        System.gc();
        System.out.println(m.get());

        /* 打印
        [B@14ae5a5
        null
         */
    }
}

虚引用

作用是用来管理堆外内存,gc线程。

DirectByteBuffer(jvm管理的对象,关联着堆外内存),如果没有任何引用指向它,得进行回收,如果直接回收对象,那么堆外内存会发生内存泄露;凡是这种,jvm对它挂一个虚引用,如果其被回收,它的对象信息会放在某个队列上(gc有一个线程一直监控着),gc就清理与之对应的堆外内存。
PhantomReference的第二个参数就是对应的队列。

import java.lang.ref.PhantomReference;
public class Test {
    public static void main(String[] args){
        PhantomReference<byte[]> m = new PhantomReference<>(new byte[10],null);
        System.out.println(m.get());

        /* 打印
        null
         */
    }
}

参考

Java四种引用类型
https://www.cnblogs.com/liyutian/p/9690974.html