java 内存 四_java最终化的内存保留问题(4)
四、
一種代替最終化的選擇
在前面一節(jié)中的示例還存在一種不確定性可能:JVM并不能保證它在最終化隊列中調(diào)用對象的終結(jié)器的順序。而來自于所有類(應(yīng)用程序,庫,等等)的終結(jié)器都是被同等對待的。因此,一個占有大量內(nèi)存或一種稀有的本地資源的對象可能受阻于終結(jié)化隊列-它們排在那些終結(jié)器進度緩慢的對象之后(不一定是惡意;也許由于懶惰的編程所致)。
看完上面達(dá)內(nèi)培訓(xùn)老師分享的的第一段內(nèi)容之后大家是不是已經(jīng)知道今天我們要為大家分享什么內(nèi)容了那?
為了避免這種類型的不確定性,你可以使用弱參考來代替最終化,例如使用死后鉤子(postmortem
hook)。如果用這種方式,你可以完全控制怎樣優(yōu)先化本地資源的回收問題,而代替依賴于JVM完成這件事情。下面的示例展示了這一技術(shù):
final
class NativeImage3 extends WeakReference {
private
int nativeImg;//指向本地圖像數(shù)據(jù)
//它釋放本地圖像;隨后對它的調(diào)用將被忽略
private
native void disposeNative();
void
dispose() {
disposeNative();
refList.remove(this);
}
static
private ReferenceQueue refQueue;
static
private List refList;
static
ReferenceQueue referenceQueue() {return refQueue;}
NativeImage3(Image3
img) {
super(img,
refQueue);
refList.add(this);
}
}
public
class Image3 {
private
NativeImage3 nativeImg;
private
Point pos;
private
Dimension dim;
public
void dispose() { nativeImg.dispose(); }
}
Image3與Image2相同。NativeImage3相似于NativeImage2,但是它的最后清理依賴于弱參考而不是最終化。NativeImage3擴展WeakReference,其參考是與之相關(guān)聯(lián)的Image3實例。請記住,當(dāng)一個參考對象的參考(此時是WeakReference)成為不可達(dá)的時,該參考對象就被添加到與之相關(guān)聯(lián)的參考隊列上。把nativeImg嵌入到參考對象本身就保證JVM會正確地把所需要的加入到隊列中(見圖6)。再強調(diào)一下,NativeImage3不應(yīng)該成為Image3的一個子類,這是基于前面所述原因。
圖6.把nativeImg嵌入到Reference對象本身
你可以決定是否一參考對象的參考物已經(jīng)被垃圾收集器以兩種方式回收:顯式地,在參考對象上調(diào)用get()方法;隱式地,通過觀察參考對象已經(jīng)在相關(guān)聯(lián)的參考隊列中排隊來實現(xiàn)。本示例中只使用了后者。
注意,參考對象僅能被垃圾收集器所發(fā)現(xiàn)并且被添加到它們的相關(guān)聯(lián)的參考隊列-只有它們本身是可達(dá)的時候。否則,它們就象任何其它不可達(dá)的對象一樣被簡單地回收。這就是為什么你把所有的NativeImage3實例添加到該靜態(tài)鏈表(實際上,任何數(shù)據(jù)結(jié)構(gòu)都會滿足):為了確保它們保持為可達(dá)的并且當(dāng)它們的參考物成為不可達(dá)的時被處理。當(dāng)然,你還必須確保當(dāng)你釋放它們時(這是通過dispose()方法來實現(xiàn)的)你從該列表中刪除了它們。
當(dāng)在一個Image3實例上顯式地調(diào)用dispose()方法時,在該實例上不會發(fā)生隨后的最后清理;正確情況下也是這樣,因為這里不需要任何東西。這個dispose()方法從靜態(tài)列表中刪除NativeImage3實例,這樣當(dāng)它的相應(yīng)的Image3實例成為不可達(dá)的時它就是不可達(dá)的。并且,如前所述,不可達(dá)的參考對象并不被添加到它們相應(yīng)的參考隊列。相反,在所有前面的使用了最終化的示例中,可最終化的對象將總是被作最終化考慮-當(dāng)它們成為不可達(dá)的時候,無論你是否已顯式地釋放它們相關(guān)聯(lián)的本地資源。
JVM將保證,當(dāng)通過垃圾收集器發(fā)現(xiàn)一個Image3實例是不可達(dá)的時候,它會把它的相應(yīng)的NativeImage3實例添加到它的相關(guān)聯(lián)的參考隊列上去。然后,由你負(fù)責(zé)把它從隊列中刪除并釋放它的本地資源。這可以通過在一個"清理"線程中,用一個如下的循環(huán)來實現(xiàn):
ReferenceQueue
refQueue =NativeImage3.referenceQueue();
while
(true) {
NativeImage3
nativeImg =(NativeImage3) refQueue.remove();
nativeImg.dispose();
}
這是一個過于簡單的實例。高級開發(fā)者能另外根據(jù)它們?nèi)绾涡枰獌?yōu)先化清理來確保不同參考對象關(guān)聯(lián)于不同的參考隊列。并且一個單個的"清理"線程可以查詢所有可用的參考隊列和根據(jù)要求的優(yōu)先級來從隊列中刪除對象。另外,你可以選擇展開(spread
out)回收資源,這樣它就會給應(yīng)用程序帶來更少的危險性。
盡管用這種方式清理資源與使用最終化相比,明顯是更復(fù)雜些,但是這也是一種更為有力量和更為靈活的方式,而且可以最小化大量的與使用最終化相關(guān)的不確定性。另外,這種方式還十分相似于最終化實際在JVM內(nèi)實現(xiàn)的方式。對于那些顯式地使用很多本地資源并且需要更多控制的工程,我推薦對它們進行清理時使用這一方法。而只要小心地使用最終化對于大多數(shù)另外的工程來說也就足夠了。
注意:本文僅討論了兩種類型的在使用最終化時產(chǎn)生的問題,也就是內(nèi)存和資源保留問題。最終化和參考類的使用也能帶來很微妙的同步問題。要想詳細(xì)了解這一點,可以參考Read
Hans-J.Boehm的《最終化,線程和基于Java技術(shù)的內(nèi)存模型》一文。
五、僅在必要時才使用最終化
本文簡短描述了最終化是怎樣在JVM中實現(xiàn)的。然后給出了有關(guān)內(nèi)存是怎樣不必被可最終化的對象所保留的示例并且概括了這種問題的解決方案。最后,我描述了一個方法-它使用弱參考來代替-這允許你用一種更為靈活和可預(yù)測的方式來執(zhí)行最后清理。
總結(jié)
以上是生活随笔為你收集整理的java 内存 四_java最终化的内存保留问题(4)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: xftp如何搜索文件_头条搜索站长平台如
- 下一篇: SQL中,where 与 having