新聞中心
本篇內(nèi)容介紹了“Java語(yǔ)言中的四種引用區(qū)別”的有關(guān)知識(shí),在實(shí)際案例的操作過(guò)程中,不少人都會(huì)遇到這樣的困境,接下來(lái)就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!
四種引用的區(qū)別
其實(shí)四種引用的區(qū)別在于GC的時(shí)候,對(duì)它們的處理不同。用一句話(huà)來(lái)概括,就是:如果一個(gè)對(duì)象GC Root可達(dá),強(qiáng)引用不會(huì)被回收,軟引用在內(nèi)存不足時(shí)會(huì)被回收,弱引用在這個(gè)對(duì)象第一次GC會(huì)被回收。
如果GC Root不可達(dá),那不論什么引用,都會(huì)被回收
虛引用比較特殊,等于沒(méi)有引用,不會(huì)影響對(duì)象的生命周期,但可以在對(duì)象被收集器回收時(shí)收到一個(gè)系統(tǒng)通知。
下面結(jié)合案例分別來(lái)講一下四種引用在面對(duì)GC時(shí)的表現(xiàn)以及它們的常見(jiàn)用途。先設(shè)置一下JVM的參數(shù):
-Xms20M -Xmx20M -Xmn10M -verbose:gc -XX:+PrintGCDetails
強(qiáng)引用
這就是我們平時(shí)最常使用的引用。只要GC的時(shí)候這個(gè)對(duì)象GC Root可達(dá),它就不會(huì)被回收。如果JVM內(nèi)存不夠了,直接拋出OOM。比如下面這段代碼就會(huì)拋出OutOfMemoryError:
public static void main(String[] args) {
List
軟引用
軟引用,當(dāng)GC的時(shí)候,如果GC Root可達(dá),如果內(nèi)存足夠,就不會(huì)被回收;如果內(nèi)存不夠用,會(huì)被回收。將上面的例子改成軟引用,就不會(huì)被OOM:
public static void main(String[] args) {
List
我們把程序改造一下,打印出GC后的前后的差別:
public static void main(String[] args) {
List> list =
new LinkedList<>();
for (int i =
0; i <
21; i++) {
SoftReference softReference =
new SoftReference<>(new byte[1024 *
1024]);
list.add(softReference);
System.out.println("gc前:" + softReference.get());
}
System.gc();
for (SoftReference softReference : list) {
System.out.println("gc后:" + softReference.get());
}
}
會(huì)發(fā)現(xiàn),打印出的日志,GC前都是有值的,而GC后,會(huì)有一些是null,代表它們已經(jīng)被回收。
而我們?cè)O(shè)置的堆大為20M,如果把循環(huán)次數(shù)改成15,就會(huì)發(fā)現(xiàn)打印出的日志,GC后沒(méi)有為null的。但通過(guò)-verbose:gc -XX:+PrintGCDetails參數(shù)能發(fā)現(xiàn),JVM還是進(jìn)行了幾次GC的,只是由于內(nèi)存還夠用,所以沒(méi)有回收。
public static void main(String[] args) {
List> list =
new LinkedList<>();
for (int i =
0; i <
15; i++) {
SoftReference softReference =
new SoftReference<>(new byte[1024 *
1024]);
list.add(softReference);
System.out.println("gc前:" + softReference.get());
}
System.gc();
for (SoftReference softReference : list) {
System.out.println("gc后:" + softReference.get());
}
}
所以軟引用的常見(jiàn)用途就呼之欲出了:緩存。尤其是那種希望這個(gè)緩存能夠持續(xù)時(shí)間長(zhǎng)一點(diǎn)的。
弱引用
軟引用,只要這個(gè)對(duì)象發(fā)生GC,就會(huì)被回收。
把上面的代碼改成軟引用,會(huì)發(fā)現(xiàn)打印出的日志,GC后全部為null。
public static void main(String[] args) {
List> list =
new LinkedList<>();
for (int i =
0; i <
15; i++) {
WeakReference weakReference =
new WeakReference<>(new byte[1024 *
1024]);
list.add(weakReference);
System.out.println("gc前:" + weakReference.get());
}
System.gc();
for (WeakReference weakReference : list) {
System.out.println("gc后:" + weakReference.get());
}
}
所以弱引用也適合用來(lái)做緩存,不過(guò)由于它是只要發(fā)生GC就會(huì)被回收,所以存活的時(shí)間比軟引用短得多,通常用于做一些非常臨時(shí)的緩存。
我們知道,WeakHashMap內(nèi)部是通過(guò)弱引用來(lái)管理entry的。它的鍵是“弱鍵”,所以在GC時(shí),它對(duì)應(yīng)的鍵值對(duì)也會(huì)從Map中刪除。
Tomcat中有一個(gè)ConcurrentCache,用到了WeakHashMap,結(jié)合ConcurrentHashMap,實(shí)現(xiàn)了一個(gè)線(xiàn)程安全的緩存,感興趣的同學(xué)可以研究一下源碼,代碼非常精簡(jiǎn),加上所有注釋?zhuān)挥卸潭?9行。
ThreadLocal中的靜態(tài)內(nèi)部類(lèi)ThreadLocalMap里面的entry是一個(gè)WeakReference的繼承類(lèi)。
使用弱引用,使得ThreadLocalMap知道ThreadLocal對(duì)象是否已經(jīng)失效,一旦該對(duì)象失效,也就是成為垃圾,那么它所操控的Map里的數(shù)據(jù)也就沒(méi)有用處了,因?yàn)橥饨缭僖矡o(wú)法訪(fǎng)問(wèn),進(jìn)而決定擦除Map中相關(guān)的值對(duì)象,Entry對(duì)象的引用,來(lái)保證Map總是保持盡可能的小。
虛引用
虛引用的設(shè)計(jì)和上面三種引用有些不同,它并不影響GC,而是為了在對(duì)象被GC時(shí),能夠收到一個(gè)系統(tǒng)通知。
那它是怎么被通知的呢?虛引用必須要配合ReferenceQueue,當(dāng)GC準(zhǔn)備回收一個(gè)對(duì)象,如果發(fā)現(xiàn)它還有虛引用,就會(huì)在回收之前,把這個(gè)虛引用加入到與之關(guān)聯(lián)的ReferenceQueue中。
那NIO是如何利用虛引用來(lái)管理內(nèi)存的呢?
DirectBuffer直接從Java堆之外申請(qǐng)一塊內(nèi)存, 這塊內(nèi)存是不直接受JVM GC管理的, 也就是說(shuō)在GC算法中并不會(huì)直接操作這塊內(nèi)存. 這塊內(nèi)存的GC是由于DirectBuffer在Java堆中的對(duì)象被GC后, 通過(guò)一個(gè)通知機(jī)制, 而將其清理掉的.
DirectBuffer內(nèi)部有一個(gè)Cleaner。這個(gè)Cleaner是PhantomReference的子類(lèi)。當(dāng)DirectBuffer對(duì)象被回收之后, 就會(huì)通知到PhantomReference。然后由ReferenceHandler調(diào)用tryHandlePending()方法進(jìn)行pending處理. 如果pending不為空, 說(shuō)明DirectBuffer被回收了, 就可以調(diào)用Cleaner的clean()進(jìn)行回收了。
上面這個(gè)方法的代碼在Reference類(lèi)里面,有興趣的同學(xué)可以去看一下那個(gè)方法的源碼。
總結(jié)
以上就是Java中四種引用的區(qū)別。一般來(lái)說(shuō),強(qiáng)引用我們都知道,虛引用很少用到。而軟引用和弱引用的區(qū)別在于回收的時(shí)機(jī):軟引用GC時(shí),發(fā)現(xiàn)內(nèi)存不夠才回收,弱引用只要一GC就會(huì)回收。
“Java語(yǔ)言中的四種引用區(qū)別”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí)可以關(guān)注創(chuàng)新互聯(lián)-成都網(wǎng)站建設(shè)公司網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!
當(dāng)前文章:Java語(yǔ)言中的四種引用區(qū)別-創(chuàng)新互聯(lián)
網(wǎng)站路徑:http://ef60e0e.cn/article/hdgcd.html