Java的四种引用类型

强软弱虚

java中的数据被类型分为了两类,它们分别是基本类型和引用类型。一般我们new出来的对象都属于引用类型的范畴。我们知道java是有垃圾回收机制的一种语言,根据垃圾回收时的策略,java将对于堆对象的引用又进行了细分,引用被分为了强引用软引用弱引用虚引用

强引用

强引用又称普通引用,它是最常见的一种引用类型,一般我们通过new关键字创建对象时,变量对于堆对象的引用就是强引用。

强引用

强引用的特点:

  • 如果堆中的一个对象被强引用指向,那么这个变量将不会被GC回收。
  • 在堆内存不够用的情况下,被强引用指向的对象也不会被回收。(宁可抛出OOM异常)
  • 被强引用指向的对象,只有在引用消失后才会被GC回收。

测试代码-1

/* 这个类用于申请堆内存 */
public class Memory {
    private byte[] alloc;

    public Memory(int size) { this.alloc = new byte[size]; }

    @Override
    protected void finalize() throws Throwable {
        super.finalize();
        System.out.println("被GC回收");
    }
}
public class Normal {
    public static void main(String[] args) throws InterruptedException {

        /* 栈变量m对new出来的Memory对象的引用为强引用 */
        Memory m = new Memory(1024 * 1024 * 20);

        /* 现在堆中的对象没有引用指向它,它要被GC回收 */
        m = null;

        System.gc(); /* 显式GC */

        /*
         * 当我们启动java程序时,默认会有两个线程,一个是我们的主线程,另一个便是GC线程。
         * 通常GC线程的优先级比较低,并且GC线程默认为守护线程,即它会在主线程退出的同
         * 时退出。
         *
         * 为了观察到GC的效果,我们让主线程休眠1s
         */
        Thread.sleep(1000);
    }

}

测试结果-1

测试结果-1

接下来我们测试强引用的另一个特点,内存不足时的处理。

测试代码-2

public class Normal {
    
    public static void main(String[] args) throws InterruptedException {

        /* 我们设定JVM参数,设置堆内存大小为25MB */


        /* 栈变量m1对new出来的Memory对象的引用为强引用 */

        /* 申请了20MB的内存,实际会大于20MB,因为我们的byte[]被Memory对象wrapper */
        Memory m1 = new Memory(1024 * 1024 * 20);
        
        System.gc();
        Thread.sleep(1000);

        /* 再申请10MB堆内存 */
        Memory m2 = new Memory(1024 * 1024 * 10);
    }

}

测试结果-2

测试结果-2

软引用

软引用的创建需要借助jdk中java.lang.ref.SoftReference这个类来创建。也就是说,我们的变量是先引用到SoftReference这个对象,SofReference这个对象再去引用我们想要设置为软引用的对象。

软引用

软引用的特点

  • 当堆内存够用时,被软引用指向的对象不会被GC回收。
  • 当堆内存不够用时,被软引用指向的对象自动的被GC回收。

测试代码-3

public class Soft_Ref {

    public static void main(String[] args) throws InterruptedException {
        /* 堆内存大小为50MB */
        /* 申请30MB */
        SoftReference<Memory> m1 = new SoftReference<>(new Memory(1024 * 1024 * 30));

        System.gc(); /* 显示调用GC */

        /* 此时内存够用,所以结果可以预见性的为GC不会回收被软引用指向的对象 */
        
        Thread.sleep(1000);
    }
}

测试结果-3

测试结果-3

测试代码-4

public class Soft_Ref {
    public static void main(String[] args) throws InterruptedException {

        /* 堆内存大小为50MB */

        /* 申请30MB */
        SoftReference<Memory> m1 = new SoftReference<>(new Memory(1024 * 1024 * 30));

        
        /* 申请20MB */
        for (int i = 0; i < 20; ++i) {
            System.out.println("[time] => " + System.currentTimeMillis());
            SoftReference<Memory> ma = new SoftReference<>(new Memory(1024 * 1024));
            Thread.sleep(200);
        }
    }
}

测试结果-4

测试结果-4

从测试结果可以看出,当内存不够用或者将要不够用时,会触发GC,GC会自动的回收那些软引用指向对象。

一定要注意,软引用指向对象的回收是在触发GC的条件下才会被回收,如果内存够用,就算显式的调用GC,软引用指向的对象也不会被回收。

弱引用

弱引用的创建方式与软引用类似,需要借助于jdk中java.lang.ref.WeakReference类去创建。

弱引用

弱引用的特点:

  • 不管什么情况,遇到GC就会回收被弱引用指向的对象。

测试代码-5

public class Weak_Ref {

    public static void main(String[] args) throws InterruptedException {
        /* 堆内存没有设置大小,为默认状态 */
        WeakReference<Memory> m = new WeakReference<>(new Memory(1024 * 1024 * 10));
        System.gc(); /* 调用GC */
        Thread.sleep(1000);
    }
}

测试结果-5

测试结果-5

虚引用

虚引用是一种十分特殊的引用,它主要用在堆外内存的管理,虚引用可以指向堆中的对象,但是没有实际的意义。

虚引用
虚引用

虚引用的特点:

  • 无法获取虚引用指向的对象的值。
  • 虚引用在被GC回收时会有通知。
  • 虚引用在遇到GC时,不管是否还有对象引用它,它都会被GC回收。

测试代码-6

public class Phantom_Ref {
    static final ArrayList<byte[]> LIST = new ArrayList<>();

    static final ReferenceQueue<Memory> QUEUE = new ReferenceQueue<>();

    public static void main(String[] args) throws InterruptedException {

        PhantomReference<Memory> m = new PhantomReference<>(new Memory(1024 * 1024 * 10), QUEUE);
        new Thread(()->{
            while (true) {
                LIST.add(new byte[1024 * 1024 ]);

                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    Thread.currentThread().interrupt();
                }
                System.out.println(m.get()); /* 虚引用指向的值永远无法被获取 */
            }
        }).start();

        new Thread(()->{
            while (true) {
                Reference<? extends Memory> poll = QUEUE.poll();
                if (poll != null) {
                    /* 虚引用在对象回收时,会进行通知 */
                    System.out.println("有虚引用被GC回收了-" + poll);
                    break;
                }
            }
        }).start();
    }
}

测试结果-6

测试结果-6

Reference

本文章参考自马士兵老师对于引用的讲解视频,在此感谢马士兵老师的讲解。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,240评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,328评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,182评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,121评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,135评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,093评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,013评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,854评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,295评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,513评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,678评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,398评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,989评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,636评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,801评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,657评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,558评论 2 352

推荐阅读更多精彩内容