我所知道的對象引用

碎碎念

JDK1.2之后對對象的引用進行了劃分,分別存在有強引用,軟引用,弱引用,虛引用

  1. 強引用(Strong Reference)

強引用是最普通的引用,如果一個對象是強引用。那么垃圾回收器絕對不會回收它。當內存空間不足時,java虛擬機會拋出OutOfMemoryError是程序異常終止,但是不會回收強引用對象。

  1. 軟引用(Soft Reference)

一個對象如果是軟引用的話,那么當程序內存不足的時候,垃圾回收器會回收它。那內存空間不緊張的時候。它就一直存在。也就意味著我們是使用它。

  1. 弱引用(Weak Reference)

弱引用相比于軟引用它的聲明周期更短。當垃圾回收器在工作的過程中,發現了弱引用對象,不管當前內存是否緊張。都會將其回收。但是GC的觸發不是特別的頻繁。所以不會那么快發現這個引用。

  1. 虛引用 (Phantom Reference)

虛引用顧名思義,就是形同虛設,與其他幾種引用都不同,虛引用并不會決定對象的生命周期。

設計一個軟引用緩存集合

由于種種因素,我們需要緩存一些數據在內存中,假設我們現在需要緩存的數據是Person類。( 注意Person對象很大,像BitMap一樣)


public class Person {
    private String name;
    private byte[] datas = new byte[1024*1024*100];

    public Person(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                '}';
    }
}

正常情況下,我們是直接使用如下的代碼


public class Main {

    public static void main(String[] args) {

        Map<Integer, Person> pp = new HashMap<>();
        for (int i = 0; i < 100; i++) {
            Person person = new Person("hello world");
            pp.put(i, person);
        }

        for (int i = 0; i < 100; i++) {
            System.out.println(pp.get(i));
        }
    }
}

但是一運行,你就會發現出現如下的錯誤

image.png

因為Person的數據量太大了,導致JVM出現了OOM。那么有沒有辦法容納下這么多的數據,而不會出現OOM呢? 嗯~ 沒有辦法。 因為JVM內存是有限制的,你沒有辦法無節制的往內存中存放東西。但是我們可以換個角度,來思考。盡可能的利用JVM內存呢?嗯~ 可以的,我們可以利用上面所說的軟引用特性來設計一個緩存集合。



/***
 * 軟引用應用設計集合
 * @param <K> Key
 * @param <V> Value
 */
public class SoftReferenceCache<K, V> {

    private Map<K, SoftReference<V>> mCache = new HashMap<>();


    /**
     * 存放數據
     *
     * @param k 數據Key
     * @param v 數據Value
     */
    public void put(K k, V v) {
        mCache.put(k, new SoftReference<V>(v));
    }


    /**
     * 存放數據
     *
     * @param k 數據Key
     * @return 返回數據Value
     */
    public V get(K k) {
        SoftReference<V> reference = mCache.get(k);
        if (reference != null) {
            return reference.get();
        }
        return null;
    }

}

然后使用上面的 SoftReferenceCache 來進行存儲

 public static void main(String[] args) {
        SoftReferenceCache<Integer, Person> softReferenceCache = new SoftReferenceCache<>();
        for (int i = 0; i < 100; i++) {
            softReferenceCache.put(i, new Person("hello world" + i));
        }

        for (int i = 0; i < 100; i++) {
            System.out.println(softReferenceCache.get(i));
        }
    }

運行后,你會發現不會出現OOM。但是會存在有被GC回收的對象。這個時候,你需要在自己的邏輯上增加三級緩存

image.png

如何知道一個對象被GC回收呢?

我們想要知道一個對象什么時候會被GC回收。就需要利用引用隊列ReferenceQueue,GC在準備回收一個對象時,如果發現它還僅有軟引用(或弱引用,或虛引用)指向它,就會在回收該對象之前,把這個軟引用(或弱引用,或虛引用)加入到與之關聯的引用隊列(ReferenceQueue)中,這樣我們就知道,對象被GC回收了。

 public static void main(String[] args) throws InterruptedException {
        ReferenceQueue<Person> queue = new ReferenceQueue<>();
        WeakReference<Person> cc = new WeakReference<>(new Person("hello"), queue);
        System.gc();
        Thread.sleep(2000);
        Object object;
        while ((object = queue.poll()) != null) {
            System.out.println("GC回收了>>>>:" + object);
        }
    }

上述代碼,可以知道cc什么時候被回收

image.png

Android 中的 Reference

  1. Android 不建議使用軟引用來做緩存,因為Android Runtime無法感知,應該通過GC來回收內存,還是增加APP的棧內存。官方推薦我們是LruCache
image.png
  1. 當我們能夠了解一個對象的銷毀時機,就意味著我們能對一些本該銷毀的對象進行反應。 也就是內存泄露的檢測。LeakCanary 底層就是使用引用隊列進行對ActivityFragment進行檢測的。

相關連接

https://developer.android.com/reference/java/lang/ref/package-summary
https://github.com/square/leakcanary

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,412評論 6 532
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,514評論 3 416
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,373評論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,975評論 1 312
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,743評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,199評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,262評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,414評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,951評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,780評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,983評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,527評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,218評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,649評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,889評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,673評論 3 391
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,967評論 2 374

推薦閱讀更多精彩內容

  • 1 Java的引用 對于Java中的垃圾回收機制來說,對象是否被應該回收的取決于該對象是否被引用。因此,引用也是J...
    高級java架構師閱讀 400評論 0 1
  • Java GarbageCollection(GC) Java不能像C/C++那樣直接對內存進行操作(內存分配和垃...
    獅_子歌歌閱讀 2,399評論 0 3
  • 一名女子和一名男子淡如君子般交心,那時無關風花雪月。男子要離開了,想要名揚天下實現抱負。女子低頭為他劍穗上纏上新流...
    是石一的一啊閱讀 333評論 0 0
  • 本周我做的練習是直播的界面優化設計,從網上找了一套界面,做了一些改版。(圖片是隨意找的,會出現跟文字不搭的情況,還...
    鄭二炮閱讀 206評論 0 1
  • 沂蒙 沂蒙又名沂蒙山區,是一個人文地理概念,主要指的是以蒙山、沂水為地域標志的革命老區,是抗日戰爭時期和解放戰爭時...
    靜篤齋閱讀 406評論 0 0