又是一個被講爛的東西,但是我還是總結一下,日後也可以自己看。
一、強引用
A a = new A(); a是強引用,new A();是對象。我們99%都是用這樣形式,不多說,不舉例。
二、軟引用
軟引用是說當內存不足時,也就是快oom之前,它會去把只有軟引用引用的對象刪除。例子如下:
結果如下:
三、弱引用
弱引用是說當第一次GC時候,刪除只有弱引用引用的對象。例子如下:
結果如下:
四、虛引用(幽靈引用)
虛引用在任何時間都可能被刪除,而且無論何時使用get方法都會返回null。他必須搭配RefrenceQueue使用,除了虛引用,軟引用和弱引用都可以使用RefrenceQueue,而且用法都一樣。這裏就用虛引用做例子。例子如下:
結果如下:
五、threadlocal之oom
很多同行發博客我覺得已經失去了初心,我認爲這是一個做技術人最純粹的東西,但是現在很多人沒有搞清楚或者複製別人的貼子,也許這也是大家認爲谷歌比百度好的原因,但我不管環境怎麼樣,我的文章一定是原創,一定是我驗證過的。
threadlocal裏有個threadlocalmap,這個map自定義了一個entry,這個entry key是弱引用,value是threadlocal的值。
1、如果你用如下方式用threadlocal(我們大多數也是這麼用的,阿里的java開發規範也是建議這麼用的)
這裏threadlocal是一個靜態私有的成員變量,我們之前有說過弱引用只有當對象只有弱引用時候纔會被GC清除,那麼這樣寫就是有一個強引用,那麼就不會出現很多文章說的出現key爲null,value有值的entry。但是這樣也會oom,比如線程太多,每個線程放到threadllocal裏數據太大,也會oom。這裏是oom第一個原因。
2、如果採用私有變量,那麼會出現網上大部分文章說的key爲null,從而導致oom的情況
原因解釋:這裏設置了threadlocal並且賦了值,但是他沒有強引用。那麼當第一次GC,時候entry裏的key會被清空,value保留值。但是僅僅這樣也是不會oom,還要有2個條件。
①就是所運行的線程不能結束,因爲線程結束threadlocalmap也沒了,自然不會oom。
②線程運行過程中不再執行set、get、remove命令
當線程運行過程中發生了GC,那麼會留下一個空key的entry。並且沒有執行set、get、remove,因爲這3個命令都會清空key爲null的entry。當滿足這兩個條件,請求線程再多一點,就會出現oom了。