" />

欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java中四種引用詳解

 更新時間:2021年12月23日 11:47:28   作者:.D..  
這篇文章主要為大家介紹了Java中的四種引用,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助

java 中的 4 種引用方式,適用于不同的場景,重點需要理解虛引用,結(jié)合文字和代碼

強(qiáng)引用

被強(qiáng)引用的對象,不會被垃圾回收器回收,JVM 寧愿拋出 OOM 也不會去回收被強(qiáng)引用的對象;

M m = new M();

軟引用

當(dāng)堆空間夠用時,GC 不會對軟引用的對象進(jìn)行回收,當(dāng)堆空間不足以分配新的空間時,觸發(fā) GC 就會對這部分對象進(jìn)行回收,通常用在緩存等領(lǐng)域。將緩存對象使用軟引用,空間不足的時候釋放這部分空間,需要再次使用的時候,重新從 DB 中加載即可。

另外軟引用可以配合隊列(ReferenceQueue) 來使用,如果軟引用引用的對象被垃圾回收,JVM 會把軟引用加入到與之關(guān)聯(lián)的引用隊列中。

/**
 * 軟引用:一般用在緩存,只要空間不足,GC 跑起來就會回收它
 * 運(yùn)行參數(shù) -Xmx200m -XX:+PrintGC
 * Created by etfox on 2021/03/01 17:06
 **/
public class TestSoftReference {
    public static void main(String[] ags) throws InterruptedException {
        //100M的緩存數(shù)據(jù)
        byte[] cacheData = new byte[100 * 1024 * 1024];
        //將緩存數(shù)據(jù)用軟引用持有
        SoftReference<byte[]> cacheRef = new SoftReference<>(cacheData);
        //將緩存數(shù)據(jù)的強(qiáng)引用去除
        cacheData = null;
        System.out.println("第一次GC前" + cacheData);
        System.out.println("第一次GC前" + cacheRef.get());
        //進(jìn)行一次GC后查看對象的回收情況
        System.gc();
        //等待GC
        Thread.sleep(500);
        System.out.println("第一次GC后" + cacheData);
        System.out.println("第一次GC后" + cacheRef.get());
        //在分配一個120M的對象,看看緩存對象的回收情況
        byte[] newData = new byte[120 * 1024 * 1024];
        System.out.println("分配后" + cacheData);
        System.out.println("分配后" + cacheRef.get());
    }
}
console==>
[GC (Allocation Failure)  4120K->1055K(15872K), 0.0016237 secs]
[Full GC (Allocation Failure)  1055K->1054K(15872K), 0.0015426 secs]
第一次GC前null
第一次GC前[B@1973e9b
[Full GC (System.gc())  103583K->103455K(118340K), 0.0015559 secs]
第一次GC后null
第一次GC后[B@1973e9b
[GC (Allocation Failure)  105575K->103455K(198016K), 0.0001733 secs]
[Full GC (Allocation Failure)  103455K->103455K(198016K), 0.0011860 secs]
[Full GC (Allocation Failure)  103455K->819K(198016K), 0.0012080 secs]
分配后null
分配后null

弱引用

弱引用的引用對象在每次 GC 時,不管當(dāng)前堆內(nèi)存大小,都會將這個對象清除。如果此對象偶爾使用,并且希望需要用到的時候可以獲取到,但是又不希望影響這個對象的回收,就可以使用弱引用來描述對象。

當(dāng)然弱引用也可以結(jié)合事件隊列使用。

/**
 * 弱引用:如果對象時偶爾使用,并且希望使用的時候就能獲取到(get),但是又不想影響此對象的垃圾收集
 * 可以引入隊列
 * Created by etfox on 2021/03/01 17:59
 **/
public class TestWeakReference {
    public static void main(String[] args) throws InterruptedException {
        //100M的緩存數(shù)據(jù)
        byte[] cacheData = new byte[100 * 1024 * 1024];
        //將緩存數(shù)據(jù)用軟引用持有
        WeakReference<byte[]> cacheRef = new WeakReference<>(cacheData);
        System.out.println("第一次GC前" + cacheData);
        System.out.println("第一次GC前" + cacheRef.get());
        //進(jìn)行一次GC后查看對象的回收情況
        System.gc();
        //等待GC
        Thread.sleep(500);
        System.out.println("第一次GC后" + cacheData);
        System.out.println("第一次GC后" + cacheRef.get());
        //將緩存數(shù)據(jù)的強(qiáng)引用去除
        cacheData = null;
        System.gc();
        //等待GC
        Thread.sleep(500);
        System.out.println("第二次GC后" + cacheData);
        System.out.println("第二次GC后" + cacheRef.get());
    }
}
console==>
[GC (Allocation Failure)  3912K->1025K(15872K), 0.0016372 secs]
[Full GC (Allocation Failure)  1025K->1024K(15872K), 0.0014157 secs]
第一次GC前[B@1973e9b
第一次GC前[B@1973e9b
[Full GC (System.gc())  103723K->103456K(118340K), 0.0016463 secs]
第一次GC后[B@1973e9b
第一次GC后[B@1973e9b
[Full GC (System.gc())  105601K->1056K(198016K), 0.0012771 secs]
第二次GC后null
第二次GC后null

虛引用

虛引用,顧名思義是虛幻的,虛引用的對象并不能在 get 的時候獲取到它。它也在我們?nèi)粘i_發(fā)中沒有適用的場景,它的主要作用是用來跟蹤一個對象的生命周期 (通常來說是直接內(nèi)存 [JDK1.5 Java 中除了由 JVM 管理的空間,還可以在內(nèi)存中直接分配對象]中的對象),一般使用在 JVM 的開發(fā)中,主要用來管理直接內(nèi)存,因為直接內(nèi)存通常 GC 無法管理這一塊內(nèi)存(C++ delete 完事),需要特殊處理。

例如 NIO 的 ByteBuffer.allocateDirect(1024); 分配內(nèi)存到直接內(nèi)存空間中,通常來說從網(wǎng)卡中讀取的數(shù)據(jù),由操作系統(tǒng)讀取到直接內(nèi)存中,在需要使用的時候,需要拷貝到 JVM 堆空間中,如果不使用 allocateDirect 就需要一個拷貝的過程,這是非常消耗時間的,

// |-- ---| | --------| |------------|
// | 網(wǎng)卡 | ==> | 直接內(nèi)存 | == copy ==> | JVM 堆空間 |
// |--- --| | ------- | |------------|

使用直接存內(nèi)存省略了拷貝的過程,俗稱 nio 的 zero copy,但是直接內(nèi)存中的對象在不需要使用的時候無法通過正常 GC 過程去管理這一塊空間,所以用到了虛引用,

解釋:

虛引用需要配合一個事件隊列一起使用,JVM GC 的時候并不是說把虛引用的引用清理掉完事,而是說會把虛引用的引用放到事件隊列當(dāng)中,垃圾回收線程會時不時的去檢查這個事件隊列,看一下引用的回收過程需不需要做一些后續(xù)善后處理(例如清理直接內(nèi)存中的對象,這玩意兒由實現(xiàn)人去弄)這就是虛引用的作用和含義了。

/**
 * 虛引用:可以通過隊列跟蹤一個對象的生命周期,一般在寫 JVM 相關(guān)的時候才會用到虛引用,主要用來管理直接內(nèi)存(C++ delete 一下子完事)
 * -Xmx20m -XX:+PrintGC
 * Created by etfox on 2021/03/03 12:14
 **/
public class TestPhantomReference {
    private static final List<Object> LIST = new LinkedList<>();
    private static final ReferenceQueue<M> QUEUE = new ReferenceQueue<>();
    public static void main(String[] args) throws InterruptedException {
        final PhantomReference<M> phantomReference = new PhantomReference<>(new M(), QUEUE);
        // 永遠(yuǎn)都會返回 null
        System.out.println(phantomReference.get());
        // ByteBuffer.allocateDirect(1024); 分配內(nèi)存到操作系統(tǒng)的空間,直接內(nèi)存的空間, JDK 1.5
        // 通常從網(wǎng)卡讀取的數(shù)據(jù),通常由系統(tǒng)讀取到直接內(nèi)存里面,如果想用,需要拷貝到 JVM 堆空間里
        // 如果不使用 allocateDirect(直接內(nèi)存) 就需要一個拷貝的過程,是非常消耗時間的
        // |-- ---|     | --------|             |------------|
        // | 網(wǎng)卡  | ==> | 直接內(nèi)存 | == copy ==> |  JVM 堆空間 |
        // |--- --|     | ------- |             |------------|
        // 使用直接內(nèi)存省略了拷貝的過程,俗稱 nio zero copy
        // 但是直接內(nèi)存中的對象在不再需要的時候無法由 JVM 去 GC 清理內(nèi)存,所以用到了虛引用
        // 虛引用需要和一個隊列一起使用,JVM GC 時并不是說會把虛引用的引用清理,而是說會把虛引用的引用放到事件隊列中
        // 垃圾回收線程可以時不時的檢查這個事件隊列,看一下這個引用的回收過程需不需要做一些善后處理(例如清理直接內(nèi)存的那個對象)
        // 這就是虛引用的作用和含義
        ByteBuffer b = ByteBuffer.allocateDirect(1024);
        new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    LIST.add(new byte[1024 * 1024]);
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(phantomReference.get());
                }
            }
        }).start();
        // 模擬垃圾回收線程
        new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    Reference<? extends M> poll = QUEUE.poll();
                    if (poll != null) {
                        System.out.println("虛引用對象被 JVM 回收了 " + poll);
                    }
                }
            }
        }).start();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    public static class M {
        @Override
        protected void finalize() throws Throwable {
            System.out.println("當(dāng)對象將被回收時, GC 會調(diào)用當(dāng)前方法");
        }
    }
}
console==>
null
[GC (Allocation Failure)  3493K->1061K(15872K), 0.0017311 secs]
當(dāng)對象將被回收時, GC 會調(diào)用當(dāng)前方法
null
null
null
[GC (Allocation Failure)  4483K->4132K(15872K), 0.0020184 secs]
null
null
null
null
[GC (Allocation Failure)  8299K->8228K(15872K), 0.0017350 secs]
null
null
null
null
[GC (Allocation Failure)  12401K->12324K(17928K), 0.0016853 secs]
[Full GC (Allocation Failure)  12324K->12324K(17928K), 0.0011354 secs]
虛引用對象被 JVM 回收了 java.lang.ref.PhantomReference@d5fbc1
null
null
null
null
null
[Full GC (Allocation Failure)  17599K->17445K(19840K), 0.0019903 secs]
null
[Full GC (Allocation Failure)  18524K->18469K(19840K), 0.0011629 secs]
[Full GC (Allocation Failure)  18469K->18232K(19840K), 0.0022320 secs]
Exception in thread "Thread-0" java.lang.OutOfMemoryError: Java heap space
	at com.pangu.TestPhantomReference$1.run(TestPhantomReference.java:41)
	at java.lang.Thread.run(Thread.java:748)

總結(jié)

本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!

相關(guān)文章

  • Java 二叉樹遍歷特別篇之Morris遍歷

    Java 二叉樹遍歷特別篇之Morris遍歷

    二叉樹的遍歷(traversing binary tree)是指從根結(jié)點出發(fā),按照某種次序依次訪問二叉樹中所有的結(jié)點,使得每個結(jié)點被訪問依次且僅被訪問一次。四種遍歷方式分別為:先序遍歷、中序遍歷、后序遍歷、層序遍歷
    2021-11-11
  • 從零開始在Centos7上部署SpringBoot項目

    從零開始在Centos7上部署SpringBoot項目

    本文主要介紹了從零開始在Centos7上部署SpringBoot項目,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-04-04
  • SpringBoot+Quartz+數(shù)據(jù)庫存儲的完美集合

    SpringBoot+Quartz+數(shù)據(jù)庫存儲的完美集合

    這篇文章主要介紹了SpringBoot+Quartz+數(shù)據(jù)庫存儲的示例代碼,本文通過實例代碼圖文相結(jié)合給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-02-02
  • springboot+springJdbc+postgresql 實現(xiàn)多數(shù)據(jù)源的配置

    springboot+springJdbc+postgresql 實現(xiàn)多數(shù)據(jù)源的配置

    本文主要介紹了springboot+springJdbc+postgresql 實現(xiàn)多數(shù)據(jù)源的配置,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-09-09
  • Java中的String對象數(shù)據(jù)類型全面解析

    Java中的String對象數(shù)據(jù)類型全面解析

    首先String不屬于8種基本數(shù)據(jù)類型,String是一個對象,因為對象的默認(rèn)值是null,所以String的默認(rèn)值也是null;但它又是一種特殊的對象,有其它對象沒有的一些特性
    2012-11-11
  • JVM?jstack實戰(zhàn)之死鎖問題詳解

    JVM?jstack實戰(zhàn)之死鎖問題詳解

    如果在生產(chǎn)環(huán)境發(fā)生了死鎖,我們將看到的是部署的程序沒有任何反應(yīng)了,這個時候我們可以借助?jstack進(jìn)行分析,下面我們實戰(zhàn)操作查找死鎖的原因
    2022-10-10
  • SpringBoot后端解決跨域問題的3種方案分享

    SpringBoot后端解決跨域問題的3種方案分享

    這篇文章主要給大家分享介紹了關(guān)于SpringBoot后端解決跨域問題的3種方案,跨域指的是瀏覽器不能執(zhí)行其他網(wǎng)站的腳本,它是由瀏覽器的同源策略造成的,是瀏覽器施加的安全限制,需要的朋友可以參考下
    2023-07-07
  • java線程池:獲取運(yùn)行線程數(shù)并控制線程啟動速度的方法

    java線程池:獲取運(yùn)行線程數(shù)并控制線程啟動速度的方法

    下面小編就為大家?guī)硪黄猨ava線程池:獲取運(yùn)行線程數(shù)并控制線程啟動速度的方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-05-05
  • Spring Boot RabbitMQ 延遲消息實現(xiàn)完整版示例

    Spring Boot RabbitMQ 延遲消息實現(xiàn)完整版示例

    本篇文章主要介紹了Spring Boot RabbitMQ 延遲消息實現(xiàn)完整版示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-05-05
  • MyBatis?Xml映射文件之字符串替換方式

    MyBatis?Xml映射文件之字符串替換方式

    這篇文章主要介紹了MyBatis?Xml映射文件之字符串替換方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-11-11

最新評論