JAVA對象引用與垃圾收集

 
影子引用
java.lang.ref.PhantomReference
Phantom Reference 主要是用來取代對象的 finalize()。程序員利用 finalize() 來進行釋放資源的同時,有可能不小心 讓此對象再度擁有 Direct Reference。但是使用 Phantom Reference 則不會有此情形發生。和 Weak Reference 以 及 SoftReference 最大的不同是:Phantom Reference 一訂要搭配着 ReferenceQueue 使用,因爲 Phantom Reference 的 get() 傳 出值一定是 null(以避免此對象不小心再度擁有 Direct Reference)。通常我們會設計一個 class 繼承 PhantomReference,然 後 override 其 clear() 來定義釋放資源等收尾的動作。當然,我寧可小心一點地使用 finalize(),也不願意自找麻煩地使用 Phantom Reference。
弱引用
java.lang.ref.WeakReference
不過,現在有了 Weak Reference 之後,這就可以迎刃而解了。如果你希望能隨時取得某對象的信息,但又不想影響此 對象的垃圾收集,那麼你應該用 Weak Reference 來記住此對象,而不是用一般的 reference。請看下面的例子:
  WeakReference wr = new WeakReference(obj);
  if (wr.get()==null) {
    System.out.println("obj 已經被清除了 ");
  } else {
  System.out.println("obj 尚未被清除,其信息是 "+obj.toString());
}
這類的技巧,在設計 Optimizer 或 Debugger 這類的程序時常會用到,因爲這類程序需要取得某對象的信息,但是不可以 影響此對象的垃圾收集。
java.lang.ref.SoftReference
  所有Soft Reference到的對象保證會在java虛擬機發生OutOfMemoryError 前被清除。Soft Reference 雖然和 Weak Reference 很類似,但是用途卻不同。SoftReference 常被用來實現 object-cache (memory-sensitive caches)之用的。 被 Soft Reference 指到的對象,即使沒有任何 Direct Reference,也不會被清除。一直要到 JVM 內存不足時且 沒有 Direct Reference 時纔會清除,如此一來 SoftReference 不但可以把對象 cache 起來,也不會造成內存不足的錯誤 (OutOfMemoryError)。
public(公衆) class ReferenceQueue
extends(擴充) Object 
        Reference(提及) queues(行列), to which registered(已註冊的) reference objects are appended(附加) by the garbage(垃圾) collector(收藏家) after the appropriate(適當的) reachability changes(改變) are detected(檢測到的)
WeakHashMap
  由於作爲key的對象將通過計算其散列函數來確定與之對應的value的位置,因此任何作
key的對象都必須實現hashCodeequals方法。hashCodeequals方法繼承自根類Object
,如果你用自定義的類當作key的話,要相當小心,按照散列函數的定義,如果兩個對象相
同,即obj1.equal
s(obj2)=true
,則它們的hashCode必須相同,但如果兩個對象不同,則它們的hashCode不一
定不同,如果兩個不同對象的hashCode相同,這種現象稱爲衝突,衝突會導致操作哈希表的
時間開銷增大,所以儘量定義好的hashCode()方法,能加快哈希表的操作。
  如果相同的對象有不同的hashCode,對哈希表的操作會出現意想不到的結果(期待的
get
方法返回null),要避免這種問題,只需要牢記一條:要同時複寫equals方法和
hashCode
方法,而不要只寫其中一個。
  Hashtable是同步的。
Transient 表明的實體可以在序列化時忽落。.transient只能用在類的成員變量上,不能用在方法裏
transient
變量不能是finalstatic
Volatile 表明變量是被幾個線程同時修改的
如何用this?請看:
class Outer{
int i;
class Inner{
class InnerInner{
void Test(){
Outer.this.i=1

}
}
}
}
意思是FP-stct,Java虛擬機進行浮點運算時,如果沒有指定stctfp關鍵字時,Java的編譯器以及運行環境在對浮點運算的表達式是採取一種近似於我行我素的行爲來完成這些作,以致於得到的結果往往無法令你滿意.而一旦使用了stctfp來聲明一個類、接口或者方法時,那麼所聲明的範圍內Java的編譯器以及運行環境會完全依照浮點規範IEEE-754來執行.因此如果你想讓你的浮點運算更加精確,而且不會因爲不同的硬件平臺所執行的結果不一致的話,那就請用關鍵字
 
對象引用應用程序設計接口是JDKTM1.2中新定義的。該應用程序設計接口允許應用程序以對象引用的方式與JVM的內存管理器進行交互。當應用程序需管理大量內存對象或者在新的Java對象創建之前需刪除原有對象時,Java對象引用應用程序設計接口具有相當大的用途,例如:
● 基於Web的應用程序常常要求顯示大量圖片,當用戶離開某一Web頁時,往往不能確定是否能夠順利的返回。在這種程序中,應用Java對象引用API可以創建這樣一個環境,即當堆內存以最小程度運行時,內存管理器創建對象。當用戶返回時,應用程序就會重新載入已經創建的圖片。
● 應用對象引用隊列可以創建這樣一個環境,當通過對象引用獲得某一對象時,應用程序得到通知。然後,應用程序就可以對相關對象進行清除操作,同時使這些對象在內存管理器中合法化。
內存管理器的工作機制
下面將首先介紹未嵌入引用對象時內存管理器的工作機制,然後討論引用對象加入之後Java堆發生的變化。
  內存管理器的作用就是識別程序中不再使用的對象,並且回收其內存。
一個Java應用程序由一系列線程組成,每個線程執行一系列方法,而每個方法通過參數或局部變量來引用對象。這些引用屬於引用集合中的一部分,直接進入應用程序。另外,引用集合中還包括類庫中定義的靜態引用變量,以及通過Java本地接口(JNI)API獲得的引用。引用集合中的所有引用對象都可以被當前應用程序獲取,而不必被回收。同樣地,這些對象可能包含對其它對象的引用,也可以被應用程序獲取,依此類推。Java堆中的其它對象視爲不可獲取的,而所有這些不可獲取的對象在內存管理中也是合法的。如果一個不可獲取的對象使用finalize()方法,任務就交給了對象所調用的收尾器(finalizer)。在內存回收期間,不具有收尾器的不可獲取對象和已經調用收尾器的對象被簡單回收。
內存回收的算法是不斷變化的,共性的方面是從引用集合中識別可獲取的對象以及回收被其它對象佔據的內存空間。
加入引用對象之後的引用與常規引用的區別在於,引用對象中的引用專門由內存管理器來處理。引用對象封裝了其它一些對象的引用,我們稱之爲指示對象。在引用對象創建的同時,也就定義了該引用對象的指示對象。
  Java對象引用
  圖1所示爲對象引用應用程序設計接口中定義的類層次。其中SoftReference類、WeakReference類和PhantomReference類中分別定義了三種引用對象以及相應的三種獲取對象的能力。因此按照由強到弱,對象可獲取程度可劃分爲如下五種類型:強獲取(strongly reachable)、次獲取(softly reachable)、弱獲取(weakly reachable)、虛獲取(phantomly reachable)和不可獲取(unreachable)。
   
  圖1 對象應用類層次
  
  根據應用程序要求,對象可以是強引用(strong references)、次引用(soft references)、弱引用(weak references)、虛引用(phantom references)的任意組合。爲了確定對象的可獲取程度,JVM內存管理器從引用集合出發遍尋堆中所有到對象的路徑。當到達某對象的任意路徑都不含有引用對象時,則稱該對象具有強獲取能力;當路徑中含有一個或幾個引用對象時,根據內存管理器所查詢的引用對象的類型分別歸爲次獲取、弱獲取、虛獲取。
  
  另外,對象引用API中還定義了引用對象隊列(java.lang.ref.ReferenceQueue),這是內存管理器對引用對象進行管理的一種簡單數據結構。值得注意的是,在進行引用對象定義時,要求phantom reference對象必須產生於一個引用對象隊列,而soft reference和weak reference對象則無此限制,如:
  
  ReferenceQueue queue = new ReferenceQueue();
  PhantomReference pr = new PhantomReference(object, queue);
  Soft References 應用實例
  
  下面以在基於web的應用程序中使用soft references爲例,來說明Java對象引用與JVM的內存管理器進行交互的原理。
  
  當用戶打開某一web頁時,applet代碼獲得圖片並且得到顯示。如果在代碼中同時創建了該圖片對象的soft references,那麼當用戶離開該web頁時,內存管理器對圖片所分配的內存是否回收做出選擇。當用戶返回該web頁時,在applet代碼中使用SoftReference.get方法就會得到圖片才內存中是否仍存在的消息。如果在內存管理器中未創建該圖片,在web頁上會很快得到顯示;否則,applet代碼就會重新獲取。
  
  下面是Example.java的完整源代碼。
  
  import java.awt.Graphics;
  import java.awt.Image;
  import java.applet.Applet;
  import java.lang.ref.SoftReference;
  public class Example extends Applet {
      SoftReference sr = null;
      public void init() {
        System.out.println("Initializing");
      }
      public void paint(Graphics g) {
        Image im = (sr == null) ? null : (Image)(sr.get());
        if (im == null) {
          System.out.println("Fetching image");
          im = getImage(getCodeBase(),"yundong.gif");
          sr = new SoftReference(im);
        }
        System.out.println("Painting");
        g.drawImage(im, 25, 25, this);
        g.drawString("運動之美",20,20);
       im = null; 
      /* Clear the strong reference to the image */
      }
  
      public void start() {
        System.out.println("Starting");
      }
  
      public void stop() {
        System.out.println("Stopping");
      }
  }
  
  在上面的代碼中,對象image是一個圖片對象,傳遞給一個SoftReference對象sr。其中image對象是sr的指示對象,sr中的引用域是從次引用(soft reference)到 image。
  
  Weak References分析
  
  對於一個穩定的對象,比如說線程類對象,當需要獲取外部數據時,在程序中應用weak references是非常理想的。如果利用引用隊列創建了某一線程的weak reference,那麼當線程不再具有強獲取能力時,應用程序得到通知,根據此通知,應用程序才能執行相關數據對象的清除工作。
  
  當內存管理器未發現strong references 和 soft references 時,我們稱對象具有弱獲取能力,即在到達該對象的路徑中至少包含一個weak reference。程序中weak references被清除一段時間後,弱獲取對象被收尾器收集。由此也可以看出,soft reference和weak reference之間的區別在於,應用soft reference時,內存管理器利用算法決定是否創建弱獲取對象,而應用weak reference時,內存管理器必須創建次獲取對象。
  
  引用對象鏈
  
  當到達某一對象的路徑中含有多個引用對象時,就構成了引用對象鏈。內存管理器按照由強到弱的順序處理引用對象,具體處理步驟包括:Soft references、 Weak references、Finalization、Phantom references和創建對象五個部分。
  
  當內存管理器未發現前三種對象引用時,我們稱對象具有虛獲取能力,即在到達該對象的路徑中至少包含一個phantom reference。虛引用對象直接被收尾器收集,而不被重新創建。當內存管理器發現只有phantom references時,對象就將處於等候phantom reference狀態,應用程序向引用隊列發出通知,然後對虛引用對象調用clear()方法,將其引用域設置爲null,最後對不可獲取對象執行收集清除處理任務。
  
  通常,對象所具有的獲取能力與引用對象集合直接路徑中的最弱連接者相同。據此可以看出:
  
  圖2(a)中,虛引用對象具有強獲取能力,其它對象均具虛獲取能力;
  
  (b)中虛引用對象和弱引用對象均具強獲取能力,故次引用對象和對象集合具有若獲取能力;
  
  (c)中虛引用對象、弱引用對象和次引用對象均具強獲取能力,那麼對象集合則具次獲取能力。
    
  圖2 引用對象鏈
  小結
  ● 引用對象API是Java2平臺中的特色之一。
  
  ● 在程序中使用引用對象API不但可以在一定程度上控制內存管理器,實現內存自動管理,還可以提高程序的穩定性和安全性。
  
  ● 引用對象鏈中各個對象的獲取能力與整個鏈相關。
 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章