大對象緩存的實現與調用原則
在UOP之數據緩存一文中我介紹了對象緩存的一般原則,對其中的大對象緩存只是簡單
介紹了基本原理.本文詳細地說明如何進行大對象緩存.
基于本欄目的類型,在本欄目中討論的內容是如何恰當地應用某種技術來進行系統設計.
而不會介紹某種基本技術.如本文涉及的對象的次(軟)/弱/虛引用的概念,這是你要自己
參看相關資料而掌握的.
大對象(FatObject)是指在創建時要耗費一定時間,或創建完成后要占用一定的空間的對
象,簡單說,就是“"來之不易“"啊.比如圖形對象,Socket連結等.所以這類對象不宜頻繁地創
建.應該盡量使用它的緩沖.對象的緩沖不僅僅指緩存對象本身,而且包括多次復用.
但因為這樣的對象占用了較大的空間,如果使用頻度不高又不能長時間放在內存中,所以在
持久與創建之間產生一個矛盾.既不能每次調都重新創建,又不能一次創建后就永久保持.
算了,這么煩的事,費那么多腦子干什么.交給JVM自己決定好了.
把大對象緩存原則交給JVM自己決定,理由是:
如果JVM發生資源回收,說明現在空間吃緊,那么這類大對象就應該騰出空間了.而平時,JVM
沒有發生資源回收,說明還有一定的空間冗余,那就盡量讓這樣的大對象活得久一些.減少
重復創建的機率.
要達到上面的條件,就是不能有強引用,如果有強引用持有這樣的大對象,那么無論如果JVM
大需要回收資源的時候不會回收這個對象.
所以,我們創建一個大對象后,要么就一直不持有這個對象的強引用,要么在強引用后要立即
將對象和引用之間的關聯打斷.
SoftReferencesr=null;//聲明一個用于存返回對象的指示.
if(sr==nullsr.get()==null){
sr=newSoftReference(newFatObject());
}
我們每次都可以從sr.get()獲取這個大對象,只要sr.get()為null,說明原來那個對象已經
被回收了,下次調用時就要重新生成.
這樣生成的對象,如果我們將它賦給了強引用句柄,如:
Imageimg=(Image)sr.get();
那么在調用img引用完成后,一定要img=null;才能打斷引用句柄img與那個大對象的關聯.
否則,在JVM進行GC時,它就不能被回收,一直占著資源不能釋放.而這樣的編程方式又不符合
常歸的編程習慣,比竟,是自動回收內存的,不象C/C++的程序員在使用對象后會記得手工
清除對象,要讓程序員每次使用完對象后都要手動執行handler=null;這樣的語句實在
不是一回事.
其實,C#的屬性是一個非常好的方式,雖然Class.Attribute象是引用一個類的字段,而實際上
是調用了getXXX方法.在java中我們只好這樣來引用緩存的大對象,雖然仍然不是最常規的習
慣,但比每次調用后都要handler=null;這樣要自然得多了:
classCacahedFatImage{
SoftReferencesr=null;
StringfilePath;
publicCacahedFatImage(StringfilePath){
this.filePath=filePath;
sr=newSoftReference(newImage(filepath));
}
publicImagegetObject(){
if(sr==nullsr.get()==null)
sr=newSoftReference(newImage(filepath));
return(Image)sr.get();
}
}
在調用的時候,先生成CacahedFatImage對象:
CacahedFatImagecfi=newCacahedFatImage();
以后在調用這個大對象的時候都以cfi.getObject()來代替img引用.
如:cfi.getObject().getWidth();
cfi.getObject().getHeight();
這樣,只要這個對象沒有被回收我們就可以隨時獲取到它,而如果JVM需要回收時,因為沒強
引用關系,它可以隨時被回收.