java的4种引用类型

目录

1 前言

2  4种引用类型

2.1 强引用

2.2 软引用

2.3 虚引用

2.4 弱引用


1 前言

java中的4种引用类型,强引用软引用弱引用虚引用。说这4种引用之前,需要先说一下垃圾回收机制中的finalize()方法,

finalize()方法是Object中的方法,它只有一个空的方法体,并且被protected修饰:

 当一个java对象被当成垃圾回收的时候,垃圾回收器会负责调用finalize()方法。

2  4种引用类型

2.1 强引用

强引用:一般来讲就是直接被new出来的对象(Object o = new Object();),只要强引用存在,垃圾回收器就不会回收被引用的对象。

为了证明上述结论,可以做以下验证。

1)重写finalize()方法,因为Object中的finalize()方法只有一个空的方法体,不方便进行测试。

public class Person {

    @Override
    protected void finalize() throws Throwable {
        super.finalize();
        System.out.println("finalize");
    }
}

2)测试方法进行测试

    public static void main(String[] args) throws IOException {
        Person person = new Person();
  
        System.gc();//触发垃圾回收
        System.out.println(person);
        System.in.read();//阻塞main线程,给垃圾回收线程执行
    }

解析:创建一个Person对象,此时是一个强引用,即便是触发了垃圾回收,垃圾回收器也不会回收被引用的对象。

结果输出了person对象地址,并没有输出finalize()方法体中语句。

 那如果将该强引用删掉呢(将person置为null就行)

    public static void main(String[] args) throws IOException {
        Person person = new Person();
        person = null;
        System.gc();//触发垃圾回收
        System.out.println("person:"+person);
        System.in.read();//阻塞main线程,给垃圾回收线程执行
    }

再次执行,发现该对象被回收掉。

2.2 软引用

软引用:如果一个对象只具有软引用,并且当前虚拟机的内存足够,那么它就不会被垃圾回收器回收,否则就会回收软引用对象。

    public static void main(String[] args) {
        SoftReference<byte[]> softReference = new SoftReference<>(new byte[1024 * 1024 * 10]);
        System.out.println("softReference:"+softReference.get());
        System.gc();
        try { //进行睡眠让垃圾回收有时间执行
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("softReference:"+softReference.get());

    }

分析下以上代码:

SoftReference<byte[]> softReference = new SoftReference<>(new byte[1024 * 1024 * 10]);

 创建了一个10m大小的byte对象,放到了软引用对象中,并且有一个softReference对象指向了软引用对象。如下:

 为了证明上述所说情况在内存足够的情况下运行。控制台输出如下:

 可以发现软引用对象并没有被垃圾回收。但是如果将虚拟机内存最大设置为20M,并且再创建一个10M的字节数组,它还会这样不会被回收吗?

 再次创建一个字节数组。

    public static void main(String[] args) {
        SoftReference<byte[]> softReference = new SoftReference<>(new byte[1024 * 1024 * 10]);
        System.out.println("softReference:"+softReference.get());
        System.gc();
        try { //进行睡眠让垃圾回收有时间执行
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("softReference:"+softReference.get());

        byte[] bytes = new byte[1024 * 1024 * 10];
        System.out.println("softReference:"+softReference.get());

    }

控制台输出:

可以发现此时,软引用对象已经被回收。

由此可以证明如果一个对象只具有软引用,并且当前虚拟机的内存足够,那么它就不会被垃圾回收器回收,否则就会回收软引用对象。

通常软引用用作缓存处理,先从软引用中获取,如果没有获取到,再从缓存中获取。

2.3 虚引用

虚引用:虚引用必须与引用队列(ReferenceQueue)一起使用,当垃圾回收器准备回收一个对象时,如果发现它有虚引用,就会把这个虚引用加入到与之相关联的队列中,然后就可以通过监听引用队列得知虚引用的回收。

private static final List<Object> LIST = new LinkedList<>();

    private static final ReferenceQueue<Person> QUEUE = new ReferenceQueue<>();

    public static void main(String[] args) {
        PhantomReference<Person> phantomReference = new PhantomReference<>(new Person(), QUEUE);
        System.out.println(phantomReference.get()); //null

        //设置-Xmx20M,向内存中放置大小
        new Thread(()->{
            while (true){
                LIST.add(new byte[1024 * 1024]);
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(phantomReference.get());
            }
        }).start();

        new Thread(()->{
            while (true) {
                Reference<? extends Person> poll = QUEUE.poll();
                if (poll != null ) {
                    System.out.println("虚引用对象被jvm回收了======="+poll);
                }
            }
        }).start();

        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }
public class Person {

    @Override
    protected void finalize() throws Throwable {
        super.finalize();
        System.out.println("finalize");
    }
}

 代码解析:

1)全局定义一个LIST集合和一个引用队列QUEUE

2)定义一个虚引用对象phantomReference并将测试回收对象Person以及队列放入其中。

3)将虚拟机大小设置最大为20M

4)设置两个线程,一个线程向内存中不断的添加大小(目的是内存满了之后垃圾回收机制回收Person类并将虚引用放入引用队列QUEUE中)另外一个线程是为了测试是否拿到放入队列中的线程。

控制台输出如下:

 发现结论是正确的。

2.4 弱引用

弱应用:垃圾回收器被触发就会回收

public class Person {

    @Override
    protected void finalize() throws Throwable {
        super.finalize();
        System.out.println("finalize");
    }
}
    public static void main(String[] args) {
        WeakReference weakReference = new WeakReference<>(new Person());
        System.out.println(weakReference.get());
        System.gc();
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(weakReference.get());
        
    }

控制台输出: 

 可以发现刚开始能够打印出弱引用地址,垃圾回收之后,它就被垃圾回收了。

通常与弱引用联系的就是threadlocal了,这个会在接下来的文章中讲到。

想要了解更多编程小知识,快来关注公众号:爪哇开发吧!每周会不定时的进行更新。

posted @ 2022-09-30 13:27  小猪不会叫  阅读(214)  评论(0)    收藏  举报  来源