1. 程式人生 > >解析Java物件引用與JVM自動記憶體管理

解析Java物件引用與JVM自動記憶體管理

象引用應用程式設計介面是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不但可以在一定程度上控制記憶體管理器,實現記憶體自動管理,還可以提高程式的穩定性和安全性。
  
  ● 引用物件鏈中各個物件的獲取能力與整個鏈相關。