[仁潤雲技術團隊]JVM之GC與記憶體分配策略

仁潤雲發表於2018-11-14

當需要排查各種記憶體溢位,記憶體洩漏問題時,當垃圾收整合為系統達到更高併發量的瓶頸的時候,我們需要對自動化的GC和記憶體分配實施必要的監控和調節。

實際上,程式計數器,虛擬機器棧和本地方法棧是執行緒隔離的,每一個棧幀中分配的記憶體在類結構一定的情況下是固定的(這裡不考慮JIT優化),因此,只有這幾個區域無需考慮記憶體分配及回收問題,因為方法結束或者執行緒結束時記憶體自然被回收了。

Java堆及方法區則不一樣,一個介面的多個實現類需求的記憶體不一樣,一個方法中多個分支需要的記憶體也不一樣,這部分記憶體的分配及回收都是動態的,GC關注的也是這部分記憶體。

物件存活嗎?

引用計數法

給物件新增一個引用計數器,每當有一個地方引用它,那麼計數器的值加1,引用失效計數器的值減1。任何時刻計數器為零的物件就是不可能被再度使用的。

主流的Java虛擬機器中沒有使用這個方法來管理記憶體。主要是它很難解決物件之間的相互迴圈引用的問題。

class GCObject {
    public Object instance = null;
}
public class GCDemo {
    public static void main(String[] args) {
        GCObject obj1 = new GCObject(); // 1
        GCObject obj2 = new GCObject(); // 2
        
		obj1.instance = obj2; // 3
        obj2.instance = obj1; // 4
        
        obj1 = null; // 5
        obj2 = null; // 6
    }
}
複製程式碼

以上分為6個步驟:

  1. GCObject的例項1引用計數加1,為1
  2. GCObject的例項2引用計數加1,為1
  3. GCObject的例項2引用計數加1,為2
  4. GCObject的例項1引用計數加1,為2
  5. 棧幀中的obj1不再指向Java堆,GCObject的例項1引用計數減1,為1
  6. 棧幀中的obj2不再指向Java堆,GCObject的例項2引用計數減1,為1

至此,產生記憶體洩漏。

可達性分析法

目前主流的虛擬機器都是採用該演算法。

可以作為GC Roots的物件:

img

  • 虛擬機器棧的棧幀的區域性變數所引用的物件。
  • 方法區的靜態變數和常量所引用的物件。
  • 本地方法棧JNI所引用的物件。

上圖中的reference1,2,3都是GC Roots物件。雖然例項3,5相互引用(連通),但是GC Roots不可達,這就是GC要回收的垃圾物件。

談談引用

在JDK 1.2之前,Java中引用的定義:如果reference型別的資料中儲存的值代表的是另一塊記憶體的起始地址,就稱這塊記憶體代表一個引用。

但是這樣很難描述一些引用的“強弱”關係。因為在一些系統的快取功能中,有一些記憶體的收集釋放需要更為的合理化。於是,引用被分為強引用,軟引用,弱引用,虛引用4種。

  • 強引用,Object obj = new Object(); 這類引用如果存在那麼GC永遠不會回收這部分記憶體。
  • 軟引用,在系統要發生記憶體溢位時,這些物件將會被GC。SoftReference類。
  • 弱引用,這些物件會存在到下一次GC之前(無論記憶體是否足夠)。WeakReference 類。
  • 虛引用,我們無法通過虛引用來訪問物件,唯一目的就是這個物件被GC之前會收到一個系統通知。PhantomReference

物件之死

在可達性演算法中不可達物件並非一定被GC。物件被GC至少需要兩次標記過程,第一次是判斷是否有同GC Roots相連線的引用鏈,如果沒有那麼判斷是否有必要執行finalize()

如果有必要執行的話,那麼將該物件放置到F-Queue中,然後通過虛擬機器建立的一個低優先順序的Finalizer執行緒執行它。

如果在這個過程中(指被標記需要執行finalize 方法到記憶體被回收這個時間段之內),物件和任意一個GC Roots相關聯,那麼物件將會逃逸。

回收方法區

HotSpot中的永久代。 廢棄常量以及無用的類。 重點關注無用的類:

  • 該類的所有例項被回收。
  • 載入該類的ClassLoader被回收。
  • 該類的Class物件沒有被引用,我們無法通過反射訪問該類的方法。

一些大量使用反射,動態代理,CGLib技術的框架以及OSGi這類頻繁定義ClassLoader的場景需要虛擬機器具備類解除安裝的功能,以保證永久代不會發生記憶體溢位。

歡迎關注:www.renrunyun.com

相關文章