1. 程式人生 > >JVM記憶體分割槽和GC回收演算法

JVM記憶體分割槽和GC回收演算法

1.JVM記憶體分割槽

1)程式計數器:程式計數器是當前執行緒所執行位元組碼的行號指示器,是私有的。如果執行的是非native方法,程式計數器儲存的是當前要執行的指令的地址;如果是native方法,則程式計數器中的值是undefined。作用:保證執行緒切換後能恢復到正確的執行位置 2)虛擬機器棧:是執行緒私有的,生命週期與執行緒相同。Java方法執行時會建立一個棧幀,存放區域性變量表,操作棧,動態連結,方法出口等資訊。 區域性變量表存放的是8種已知的基本資料型別,物件的引用和指令地址,一般在編譯期就完成分配。當執行緒請求的棧深度超過超過虛擬機器所允許的棧深度就會丟擲StackOverFlowError,當虛擬機器棧動態擴充套件,申請不到足夠的記憶體空間時,就會丟擲OutOfMemoryError 3)本地方法棧:作用同虛擬機器棧,只是為native方法服務(native方法,非Java語言寫的方法,一般為C/C++編寫的程式碼) 4)堆:Java虛擬機器記憶體管理中最大的一塊,是所有執行緒共享的一個記憶體區域,在虛擬機器啟動時就建立,存放物件例項。這一部分是垃圾回收器管理的主要區域。 一般劃分為一塊Eden和兩塊Survivor,預設大小為8:1:1 5)方法區:和Java堆一樣是執行緒共享的,存放類載入資訊、常量和靜態變數,即時編譯器編譯後的程式碼等。對於HotSpot虛擬機器來說,這一塊也是GC回收的範圍。 方法區中有一個區域是執行時常量池,存放編譯期生成的各種字面量和符號引用。Java虛擬機器對Class檔案的每一部分的格式都有嚴格的規定,每一個位元組用於儲存哪種資料都必須符合規範上的要求,這樣才會被虛擬機器認可、裝載和執行。但對於執行時常量池,Java虛擬機器沒有做任何細節要求,不同的提供商實現的虛擬機器可以按照自己的需要來實現這個記憶體區域。

2.GC回收演算法

這裡只介紹幾個常見的GC演算法 判斷是否為垃圾 1)引用計數法:堆中的每個物件對應一個引用計數器(初始值為1),當物件被賦予任何變數時引用計數器加1,當某個變數引用不在作用域則減1。引用計數器減到0時則可以將物件回收。實際中使用較少,微軟的COM技術就使用了引用計數法。缺點:無法解決迴圈引用的問題,A引用B,B引用A,但無任何其他引用A或B 2)根搜尋演算法(HotSpot虛擬機器採用的方式) 從“GC Roots"開始,向下搜尋,走過的路徑稱為引用鏈。一個物件到GC Roots沒有任何引用鏈則不可到達物件。 可以作為GC Roots的物件: 虛擬機器棧中引用的物件 方法區中靜態變數引用的物件 方法區中常量引用的物件 本地方法棧中JNI引用的物件 回收方法區,主要回收兩部分內容:廢棄常量和無用的類。 廢棄常量:沒有被任何物件引用常量池中的常量 無用的類: 1)該類的所有例項已經被回收 2)載入該類的ClassLoader已經被回收 3)該類的java.lang.Class物件沒有在任何其他地方被引用 幾種常見的GC演算法 1)標記-清除演算法:首先標記出所有需要回收的物件(使用根搜尋演算法進行兩次標記),然後進行回收。 缺點:容易產生大量記憶體碎片。
2)複製演算法: Eden和一塊Survivor的存活物件拷貝到另一塊Survivor上,當Survivor空間不夠則進入老年代。複製演算法適用於新生代,因為垃圾物件多於存活物件,複製演算法更高效 優點:解決了記憶體碎片問題,但是內存摺半。(圖片引用http://www.cnblogs.com/AloneSword/p/4262255.html) 3)標記-整理演算法: 結合前兩個演算法的優點,適合用於老年代的演算法(存活物件多於垃圾物件)。 標記後不復制,而是將存活物件壓縮到記憶體的一端,然後清理邊界外的所有物件。 4)分代回收演算法: 對不同記憶體區域採用不同的回收演算法,一般區分老年代和新生代。 附:常見垃圾收集器介紹 1)Serial收集器是最基本、歷史最悠久的垃圾收集器,它是一個單執行緒的收集器。進行垃圾回收時,必須暫停其他所有的工作執行緒,直到它收集結束。優點是高效簡單,適用於使用者桌面應用的虛擬機器。 2)Parallel Scavenge收集器是一個新生代收集器,也是一個使用複製演算法的收集器,又是並行的多執行緒的收集器。它的關注點與其他收集器不同,CMS收集器等關注的是儘可能縮短垃圾收集時使用者執行緒的停頓時間,適用於與使用者互動的程式,但它關注的是吞吐量(吞吐量=使用者程式碼執行時間/(使用者程式碼執行時間+垃圾收集時間)),適用的是後臺運算的程式。 3)CMS收集器,基於“標記-清除”演算法實現,運作過程分為四個步驟:初始標記、併發標記、重新標記和併發清除。初始標記只標記和GC Roots直接關聯的物件,併發標記就是進行GC Roots Tracing的過程,而重新標記則是對併發標記期間由於使用者程式繼續執行而導致標記產生變動的那一部分物件的標記記錄的修正,併發清除就是進行垃圾回收了。最大的特點是最短停頓回收時間。 4)G1收集器,基於“標記-整理”演算法,不會產生記憶體碎片,而且能夠精確的控制停頓(將Java堆劃分為很多大小固定的區域,並且跟蹤這些區域的垃圾堆積程度,每次優先回收垃圾最多的區域)。