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

Java中的四種引用類型之強(qiáng)引用、軟引用、弱引用和虛引用及用法詳解

 更新時間:2025年08月18日 11:32:15   作者:北辰alk  
Java的四種引用類型(強(qiáng)、軟、弱、虛)控制對象生命周期,分別在不同內(nèi)存壓力下回收,適用于緩存、資源清理等場景,配合ReferenceQueue實(shí)現(xiàn)高效內(nèi)存管理,本文將全面剖析這四種引用類型的概念、用法、實(shí)現(xiàn)原理以及實(shí)際應(yīng)用場景,感興趣的朋友一起看看吧

Java提供了四種不同強(qiáng)度的引用類型,它們直接影響對象的生命周期和垃圾收集行為。理解這些引用類型的區(qū)別對于編寫高效、內(nèi)存友好的Java程序至關(guān)重要。本文將全面剖析這四種引用類型的概念、用法、實(shí)現(xiàn)原理以及實(shí)際應(yīng)用場景。

一、引用類型概述

Java中的引用類型決定了對象與垃圾收集器(GC)的互動方式:

引用類型GC行為用途場景
強(qiáng)引用默認(rèn)永不回收普通對象引用
軟引用SoftReference內(nèi)存不足時回收內(nèi)存敏感緩存
弱引用WeakReference下次GC時回收規(guī)范化映射、臨時緩存
虛引用PhantomReference隨時可能回收對象回收跟蹤、清理操作

二、強(qiáng)引用(Strong Reference)

2.1 基本概念

強(qiáng)引用是Java程序中最常見的引用類型,也是默認(rèn)的引用方式。只要強(qiáng)引用存在,對象就永遠(yuǎn)不會被垃圾收集器回收。

Object obj = new Object(); // 強(qiáng)引用

2.2 特點(diǎn)

  • 生命周期:只要引用鏈可達(dá),對象就始終存活
  • 回收條件:顯式置為null或超出作用域
  • 內(nèi)存泄漏:不當(dāng)使用會導(dǎo)致內(nèi)存泄漏

2.3 示例分析

public class StrongReferenceDemo {
    public static void main(String[] args) {
        Object strongRef = new Object(); // 強(qiáng)引用
        // 取消強(qiáng)引用
        strongRef = null;
        // 此時對象可以被GC回收
        System.gc();
    }
}

2.4 內(nèi)存泄漏場景

public class MemoryLeakDemo {
    private static List<Object> list = new ArrayList<>();
    public static void main(String[] args) {
        for (int i = 0; i < 100; i++) {
            Object obj = new Object();
            list.add(obj); // 靜態(tài)集合持有強(qiáng)引用
            obj = null; // 無效操作,因?yàn)閘ist仍持有引用
        }
        // 即使obj=null,對象仍然無法被回收
    }
}

三、軟引用(SoftReference)

3.1 基本概念

軟引用描述一些還有用但非必需的對象。只有在內(nèi)存不足時(OOM前),GC才會回收這些對象。

SoftReference<Object> softRef = new SoftReference<>(new Object());

3.2 特點(diǎn)

  • 內(nèi)存敏感:在內(nèi)存充足時表現(xiàn)如強(qiáng)引用
  • 回收策略:內(nèi)存不足時根據(jù)LRU算法回收
  • 使用場景:適合實(shí)現(xiàn)內(nèi)存敏感緩存

3.3 實(shí)現(xiàn)原理

public class SoftReference<T> extends Reference<T> {
    // 由JVM維護(hù)的時間戳,記錄最后訪問時間
    private long timestamp;
    public SoftReference(T referent) {
        super(referent);
        this.timestamp = clock;
    }
    // JVM在GC時會調(diào)用此方法
    void updateTimestamp() {
        this.timestamp = clock;
    }
}

3.4 緩存示例

public class ImageCache {
    private final Map<String, SoftReference<BufferedImage>> cache = new HashMap<>();
    public BufferedImage getImage(String path) {
        BufferedImage image = null;
        // 檢查緩存
        SoftReference<BufferedImage> ref = cache.get(path);
        if (ref != null) {
            image = ref.get();
        }
        // 緩存未命中
        if (image == null) {
            image = loadImageFromDisk(path);
            cache.put(path, new SoftReference<>(image));
        }
        return image;
    }
    private BufferedImage loadImageFromDisk(String path) {
        // 實(shí)際實(shí)現(xiàn)從磁盤加載圖像
        return null;
    }
}

3.5 回收測試

public class SoftReferenceDemo {
    public static void main(String[] args) {
        SoftReference<byte[]> softRef = new SoftReference<>(new byte[1024 * 1024 * 10]); // 10MB
        System.out.println("GC前: " + softRef.get());
        System.gc();
        System.out.println("GC后(內(nèi)存充足): " + softRef.get());
        try {
            byte[] bigArray = new byte[1024 * 1024 * 100]; // 強(qiáng)制OOM
        } catch (OutOfMemoryError e) {
            System.out.println("OOM后: " + softRef.get()); // 可能為null
        }
    }
}

四、弱引用(WeakReference)

4.1 基本概念

弱引用描述非必需對象,無論內(nèi)存是否充足,只要發(fā)生GC就會被回收。

WeakReference<Object> weakRef = new WeakReference<>(new Object());

4.2 特點(diǎn)

  • 生命周期短:只能存活到下一次GC
  • 自動回收:無需手動清除
  • 使用場景:規(guī)范化映射、臨時緩存

4.3 WeakHashMap實(shí)現(xiàn)

public class WeakHashMap<K,V> extends AbstractMap<K,V> implements Map<K,V> {
    // 使用弱引用作為Entry的key
    private static class Entry<K,V> extends WeakReference<K> implements Map.Entry<K,V> {
        V value;
        int hash;
        Entry<K,V> next;
        Entry(K key, V value, ReferenceQueue<K> queue, int hash, Entry<K,V> next) {
            super(key, queue); // key被弱引用持有
            this.value = value;
            this.hash = hash;
            this.next = next;
        }
    }
}

4.4 緩存示例

public class WeakCache<K,V> {
    private final Map<K, WeakReference<V>> cache = new HashMap<>();
    public void put(K key, V value) {
        cache.put(key, new WeakReference<>(value));
    }
    public V get(K key) {
        WeakReference<V> ref = cache.get(key);
        return ref != null ? ref.get() : null;
    }
    // 定期清理null值的WeakReference
    public void cleanUp() {
        cache.entrySet().removeIf(entry -> 
            entry.getValue() == null || entry.getValue().get() == null);
    }
}

4.5 回收測試

public class WeakReferenceDemo {
    public static void main(String[] args) {
        WeakReference<Object> weakRef = new WeakReference<>(new Object());
        System.out.println("GC前: " + weakRef.get());
        System.gc();
        // 注意:這里不能保證GC立即執(zhí)行,可能需要多次調(diào)用或增加內(nèi)存壓力
        System.out.println("GC后: " + weakRef.get()); // 很可能為null
    }
}

五、虛引用(PhantomReference)

5.1 基本概念

虛引用是最弱的引用類型,無法通過它獲取對象實(shí)例,主要用于跟蹤對象被回收的狀態(tài)。

ReferenceQueue<Object> queue = new ReferenceQueue<>();
PhantomReference<Object> phantomRef = new PhantomReference<>(new Object(), queue);

5.2 特點(diǎn)

  • 不可達(dá)性:get()始終返回null
  • 回收通知:通過ReferenceQueue獲得回收通知
  • 使用場景:精細(xì)化的對象回收后處理

5.3 實(shí)現(xiàn)原理

public class PhantomReference<T> extends Reference<T> {
    public T get() {
        return null; // 始終返回null
    }
    public PhantomReference(T referent, ReferenceQueue<? super T> q) {
        super(referent, q);
    }
}

5.4 資源清理示例

public class ResourceCleaner {
    private static final ReferenceQueue<Object> queue = new ReferenceQueue<>();
    private static final List<CleanupReference> references = new ArrayList<>();
    public static void register(Object resource, Runnable cleanupAction) {
        references.add(new CleanupReference(resource, cleanupAction, queue));
    }
    public static void cleanup() {
        CleanupReference ref;
        while ((ref = (CleanupReference) queue.poll()) != null) {
            ref.cleanup();
            references.remove(ref);
        }
    }
    private static class CleanupReference extends PhantomReference<Object> {
        private final Runnable cleanupAction;
        CleanupReference(Object referent, Runnable cleanupAction, ReferenceQueue<? super Object> q) {
            super(referent, q);
            this.cleanupAction = cleanupAction;
        }
        void cleanup() {
            cleanupAction.run();
        }
    }
}

5.5 使用示例

public class PhantomReferenceDemo {
    public static void main(String[] args) {
        Object resource = new Object();
        // 注冊清理操作
        ResourceCleaner.register(resource, () -> 
            System.out.println("資源被回收,執(zhí)行清理操作"));
        // 取消強(qiáng)引用
        resource = null;
        // 觸發(fā)GC
        System.gc();
        // 處理清理操作
        ResourceCleaner.cleanup();
    }
}

六、ReferenceQueue的作用

引用隊(duì)列(ReferenceQueue)與軟/弱/虛引用配合使用,主要用途:

  1. 跟蹤引用狀態(tài):當(dāng)引用對象被回收時,引用本身會被加入隊(duì)列
  2. 執(zhí)行后續(xù)操作:通過輪詢隊(duì)列執(zhí)行清理工作
  3. 避免引用堆積:及時清理無用的Reference對象

6.1 使用模式

ReferenceQueue<Object> queue = new ReferenceQueue<>();
WeakReference<Object> ref = new WeakReference<>(new Object(), queue);
// 在另一個線程中處理隊(duì)列
new Thread(() -> {
    try {
        while (true) {
            Reference<?> r = queue.remove();
            System.out.println("對象被回收: " + r);
            // 執(zhí)行清理操作
        }
    } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
    }
}).start();

6.2 各引用類型與隊(duì)列

引用類型入隊(duì)時機(jī)典型用途
軟引用對象被回收且內(nèi)存不足緩存清理通知
弱引用對象被回收WeakHashMap維護(hù)
虛引用對象被回收資源精確釋放

七、四種引用的對比總結(jié)

7.1 特性對比表

特性強(qiáng)引用軟引用弱引用虛引用
回收強(qiáng)度不回收內(nèi)存不足時回收下次GC回收隨時可能回收
get()返回值對象本身對象本身(回收前)對象本身(回收前)始終null
引用隊(duì)列不支持支持支持必須配合使用
典型用途普通對象引用內(nèi)存敏感緩存規(guī)范化映射資源清理跟蹤
實(shí)現(xiàn)類-SoftReferenceWeakReferencePhantomReference

7.2 生命周期圖示

八、實(shí)際應(yīng)用場景

8.1 緩存實(shí)現(xiàn)選擇

強(qiáng)引用緩存

Map<String, Object> cache = new HashMap<>(); // 可能內(nèi)存泄漏

軟引用緩存

Map<String, SoftReference<Object>> cache = new HashMap<>(); // 自動釋放

弱引用緩存

Map<String, WeakReference<Object>> cache = new HashMap<>(); // 短期緩存

8.2 監(jiān)聽器管理

public class ListenerManager {
    private final Map<EventListener, WeakReference<Listener>> listeners = new WeakHashMap<>();
    public void addListener(EventListener listener) {
        listeners.put(listener, new WeakReference<>(listener));
    }
    // 無需顯式移除,GC會自動清理
}

8.3 資源清理最佳實(shí)踐

public class ResourceHolder implements AutoCloseable {
    private final Object resource;
    private final PhantomReference<Object> phantomRef;
    public ResourceHolder(Object resource) {
        this.resource = resource;
        this.phantomRef = new PhantomReference<>(resource, cleanupQueue);
    }
    @Override
    public void close() {
        // 顯式清理
        cleanupResource(resource);
    }
    // 防止忘記調(diào)用close()
    protected void finalize() throws Throwable {
        if (resource != null) {
            cleanupResource(resource);
        }
    }
    private static void cleanupResource(Object resource) {
        // 實(shí)際清理邏輯
    }
}

九、常見問題與解決方案

9.1 內(nèi)存泄漏診斷

問題:即使使用弱引用,內(nèi)存仍在增長

解決方案

  1. 檢查是否有強(qiáng)引用意外保留
  2. 確保正確使用ReferenceQueue清理
  3. 使用MAT等工具分析內(nèi)存快照

9.2 引用隊(duì)列處理延遲

問題:對象已回收但引用未入隊(duì)

解決方案

  1. 確保有活躍線程處理隊(duì)列
  2. 適當(dāng)調(diào)用System.gc()(僅測試環(huán)境)
  3. 增加內(nèi)存壓力觸發(fā)GC

9.3 緩存性能優(yōu)化

問題:軟引用緩存頻繁重建

解決方案

  1. 調(diào)整JVM內(nèi)存參數(shù)(-Xmx)
  2. 實(shí)現(xiàn)多級緩存(強(qiáng)引用+軟引用)
  3. 使用專業(yè)緩存庫(Caffeine, Ehcache)

十、總結(jié)

Java的四種引用類型提供了不同層次的對象生命周期控制:

  1. 強(qiáng)引用:默認(rèn)選擇,確保對象長期存活
  2. 軟引用:實(shí)現(xiàn)內(nèi)存敏感緩存,平衡性能與內(nèi)存使用
  3. 弱引用:避免干預(yù)GC行為,適合規(guī)范化映射
  4. 虛引用:最精細(xì)的回收跟蹤,用于資源清理

正確運(yùn)用這些引用類型可以:

  • 預(yù)防內(nèi)存泄漏
  • 優(yōu)化內(nèi)存使用
  • 實(shí)現(xiàn)高效的緩存策略
  • 精確控制資源生命周期

理解這些引用類型的差異和適用場景,是成為Java高級開發(fā)者的重要一步。在實(shí)際開發(fā)中,應(yīng)根據(jù)具體需求選擇合適的引用類型,并配合ReferenceQueue等機(jī)制實(shí)現(xiàn)健壯的內(nèi)存管理。

到此這篇關(guān)于Java中的四種引用類型之強(qiáng)引用、軟引用、弱引用和虛引用及用法詳解的文章就介紹到這了,更多相關(guān)java 強(qiáng)引用 軟引用 弱引用和虛引用內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Centos中yum方式安裝java的實(shí)現(xiàn)示例

    Centos中yum方式安裝java的實(shí)現(xiàn)示例

    這篇文章主要介紹了Centos中yum方式安裝java的實(shí)現(xiàn)示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-04-04
  • spring中FactoryBean中的getObject()方法實(shí)例解析

    spring中FactoryBean中的getObject()方法實(shí)例解析

    這篇文章主要介紹了spring中FactoryBean中的getObject()方法實(shí)例解析,分享了相關(guān)代碼示例,小編覺得還是挺不錯的,具有一定借鑒價值,需要的朋友可以參考下
    2018-02-02
  • 解決response.setHeader設(shè)置下載文件名無效的問題

    解決response.setHeader設(shè)置下載文件名無效的問題

    這篇文章主要介紹了解決response.setHeader設(shè)置下載文件名無效的問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-01-01
  • Java創(chuàng)建和啟動線程的兩種方式實(shí)例分析

    Java創(chuàng)建和啟動線程的兩種方式實(shí)例分析

    這篇文章主要介紹了Java創(chuàng)建和啟動線程的兩種方式,結(jié)合實(shí)例形式分析了java多線程創(chuàng)建、使用相關(guān)操作技巧與注意事項(xiàng),需要的朋友可以參考下
    2019-09-09
  • 全局請求添加TraceId輕松看日志

    全局請求添加TraceId輕松看日志

    這篇文章主要為大家介紹了全局請求添加TraceId,更加方便輕松的看日志,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-09-09
  • Java實(shí)現(xiàn)的微信公眾號獲取微信用戶信息示例

    Java實(shí)現(xiàn)的微信公眾號獲取微信用戶信息示例

    這篇文章主要介紹了Java實(shí)現(xiàn)的微信公眾號獲取微信用戶信息,結(jié)合實(shí)例形式分析了Java微信公眾號獲取微信用戶信息相關(guān)原理、步驟與操作注意事項(xiàng),需要的朋友可以參考下
    2019-10-10
  • ssm整合shiro使用詳解

    ssm整合shiro使用詳解

    這篇文章主要介紹了ssm整合shiro使用詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-04-04
  • SpringBoot?SpringSecurity?JWT實(shí)現(xiàn)系統(tǒng)安全策略詳解

    SpringBoot?SpringSecurity?JWT實(shí)現(xiàn)系統(tǒng)安全策略詳解

    Spring?Security是Spring的一個核心項(xiàng)目,它是一個功能強(qiáng)大且高度可定制的認(rèn)證和訪問控制框架。它提供了認(rèn)證和授權(quán)功能以及抵御常見的攻擊,它已經(jīng)成為保護(hù)基于spring的應(yīng)用程序的事實(shí)標(biāo)準(zhǔn)
    2022-11-11
  • java list去重操作實(shí)現(xiàn)方式

    java list去重操作實(shí)現(xiàn)方式

    本文主要介紹了java list 去重的方法,其中有帶類型寫法和不帶類型寫法,并舉例測試,具有一定參考借鑒價值,希望能對有需要的小伙伴有所幫助
    2016-07-07
  • Spring JDK動態(tài)代理實(shí)現(xiàn)過程詳解

    Spring JDK動態(tài)代理實(shí)現(xiàn)過程詳解

    這篇文章主要介紹了Spring JDK動態(tài)代理實(shí)現(xiàn)過程詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-02-02

最新評論