我所知道的對象引用

碎碎念

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

  1. 強引用(Strong Reference)

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

  1. 軟引用(Soft Reference)

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

  1. 弱引用(Weak Reference)

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

  1. 虛引用 (Phantom Reference)

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

設計一個軟引用緩存集合

由于種種因素,我們需要緩存一些數(shù)據(jù)在內(nèi)存中,假設我們現(xiàn)在需要緩存的數(shù)據(jù)是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));
        }
    }
}

但是一運行,你就會發(fā)現(xiàn)出現(xiàn)如下的錯誤

image.png

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



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

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


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


    /**
     * 存放數(shù)據(jù)
     *
     * @param k 數(shù)據(jù)Key
     * @return 返回數(shù)據(jù)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));
        }
    }

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

image.png

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

我們想要知道一個對象什么時候會被GC回收。就需要利用引用隊列ReferenceQueue,GC在準備回收一個對象時,如果發(fā)現(xiàn)它還僅有軟引用(或弱引用,或虛引用)指向它,就會在回收該對象之前,把這個軟引用(或弱引用,或虛引用)加入到與之關聯(lián)的引用隊列(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來回收內(nèi)存,還是增加APP的棧內(nèi)存。官方推薦我們是LruCache
image.png
  1. 當我們能夠了解一個對象的銷毀時機,就意味著我們能對一些本該銷毀的對象進行反應。 也就是內(nèi)存泄露的檢測。LeakCanary 底層就是使用引用隊列進行對Activity、Fragment進行檢測的。

相關連接

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

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

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

友情鏈接更多精彩內(nèi)容