Java 中的 "弱" 引用有啥用?

Java技術(shù)棧
www.javastack.cn
關(guān)注閱讀更多優(yōu)質(zhì)文章
作者:telami
來(lái)源:www.telami.cn/2017/weak-reference/
推薦閱讀:Java 強(qiáng)、弱、軟、虛,你屬于哪一種?
Java里一個(gè)對(duì)象obj被創(chuàng)建時(shí),被放在堆里。當(dāng)GC運(yùn)行的時(shí)候,發(fā)現(xiàn)沒(méi)有任何引用指向obj,那么就會(huì)回收obj對(duì)象的堆內(nèi)存空間。
換句話(huà)說(shuō),一個(gè)對(duì)象被回收, 必須滿(mǎn)足兩個(gè)條件:
Object?c?=?new?Car();????
c=null;
所以, java中引入了weak reference。
Object?c?=?new?Car();?//只要c還指向car?object,?car?object就不會(huì)被回收?-->(強(qiáng)引用)
當(dāng)一個(gè)對(duì)象僅僅被weak reference指向, 而沒(méi)有任何其他strong reference指向的時(shí)候, 如果GC運(yùn)行, 那么這個(gè)對(duì)象就會(huì)被回收。另外,關(guān)注公眾號(hào)Java技術(shù)棧,在后臺(tái)回復(fù):面試,可以獲取我整理的 JVM 系列面試題和答案,非常齊全。
下面這個(gè)是網(wǎng)上的例子,首先定義一個(gè)實(shí)體類(lèi):
public?class?Car?{
????private?double?????price;
????private?String????color;
????public?Car(double?price,?String?color)
????{
????????this.price?=?price;
????????this.color?=?color;
????}
????public?double?getPrice()
????{
????????return?price;
????}
????public?String?getColor()
????{
????????return?color;
????}
????public?String?toString()
????{
????????return?"This?car?is?a?"?+?this.color?+?"?car,?costs?$"?+?price;
????}
}
一般使用WeakReference的時(shí)候都會(huì)定義一個(gè)類(lèi)繼承自WeakReference,在這個(gè)類(lèi)中再定義一些別的屬性,這里就不定義別的屬性了:
public?class?WeakReferenceCar?extends?WeakReference
{
????public?WeakReferenceCar(Car?car)
????{
????????super(car);
????}
}
main函數(shù)調(diào)用一下,當(dāng)然為了更清楚地看到GC的效果,設(shè)置虛擬機(jī)參數(shù)”-XX:+PrintGCDetails”:
public?static?void?main(String[]?args)
{
????Car?car?=?new?Car(2000.0,?"red");
????WeakReferenceCar?wrc?=?new?WeakReferenceCar(car);
????wrc.setStr("111");
????int?i?=?0;
????while?(true)
????{
????????if?(wrc.get()?!=?null)
????????{
????????????i++;
????????????System.out.println("WeakReferenceCar's?Car?is?alive?for?"?+?i?+?",?loop?-?"?+?wrc);
????????}
????????else
????????{
????????????System.out.println("WeakReferenceCar's?Car?has?bean?collected");
????????????break;
????????}
????}
}
最后是運(yùn)行結(jié)果:
WeakReferenceCar's?Car?is?alive?for?68450,?loop?-?interview.WeakReferenceCar@776ec8df
WeakReferenceCar's?Car?is?alive?for?68451,?loop?-?interview.WeakReferenceCar@776ec8df
WeakReferenceCar's?Car?is?alive?for?68452,?loop?-?interview.WeakReferenceCar@776ec8df
WeakReferenceCar's?Car?is?alive?for?68453,?loop?-?interview.WeakReferenceCar@776ec8df
[GC?(Allocation?Failure)?[PSYoungGen:?34304K->1000K(38400K)]?34320K->1016K(125952K),?0.0015129?secs]?[Times:?user=0.02?sys=0.02,?real=0.00?secs]?
WeakReferenceCar's?Car?is?alive?for?68454,?loop?-?interview.WeakReferenceCar@776ec8df
WeakReferenceCar's?Car?has?bean?collected
Heap
PSYoungGen??????total?38400K,?used?1986K?[0x00000000d5e00000,?0x00000000da900000,?0x0000000100000000)
eden?space?33280K,?2%?used?[0x00000000d5e00000,0x00000000d5ef6b70,0x00000000d7e80000)
from?space?5120K,?19%?used?[0x00000000d7e80000,0x00000000d7f7a020,0x00000000d8380000)
to???space?5120K,?0%?used?[0x00000000da400000,0x00000000da400000,0x00000000da900000)
ParOldGen???????total?87552K,?used?16K?[0x0000000081a00000,?0x0000000086f80000,?0x00000000d5e00000)
object?space?87552K,?0%?used?[0x0000000081a00000,0x0000000081a04000,0x0000000086f80000)
Metaspace???????used?3547K,?capacity?4564K,?committed?4864K,?reserved?1056768K
class?space????used?381K,?capacity?388K,?committed?512K,?reserved?1048576K
可以看到在68454循環(huán)之后,WeakReferenceCar關(guān)聯(lián)的對(duì)象Car被回收掉了,注意是弱引用關(guān)聯(lián)的對(duì)象car被回收,而不是弱引用本身wrc被回收。
WeakReference的一個(gè)特點(diǎn)是它何時(shí)被回收是不可確定的, 因?yàn)檫@是由GC運(yùn)行的不確定性所確定的. 所以, 一般用weak reference引用的對(duì)象是有價(jià)值被cache, 而且很容易被重新被構(gòu)建, 且很消耗內(nèi)存的對(duì)象.
在weak reference指向的對(duì)象被回收后, weak reference本身其實(shí)也就沒(méi)有用了. java提供了一個(gè)ReferenceQueue來(lái)保存這些所指向的對(duì)象已經(jīng)被回收的reference. 用法是在定義WeakReference的時(shí)候?qū)⒁粋€(gè)ReferenceQueue的對(duì)象作為參數(shù)傳入構(gòu)造函數(shù)。






關(guān)注Java技術(shù)棧看更多干貨


