1. 程式人生 > >JVM記憶體分割槽和垃圾回收GC機制

JVM記憶體分割槽和垃圾回收GC機制

JVM記憶體分割槽

JVM(Java virtual machine),即Java虛擬機器,它的厲害之處在於平臺無關性,“一處編寫,到處執行”。JVM通過執行目標位元組碼(.class),解釋在不同平臺上的機器執行,所以在具體的平臺上並不產生直接依賴。

JVM的記憶體空間主要有5種分割槽情況:
1. 執行緒計數器:一塊較小的記憶體空間,每個執行緒都有自己的執行緒計數器,用於完成不同執行緒上下文切換,如果呼叫的是本地方法,pc暫存器不儲存任何資訊。
2. 堆區(Heap):所有執行緒共享堆空間,主要存放物件例項與陣列,new建立的物件記憶體都在此分配,因為執行緒共享,所以需要加鎖造成new的開銷比較大。
3. 棧區(stack):棧與執行緒計數器一樣,都是執行緒獨有,棧的生命週期與執行緒的生命週期同步。每一次方法執行時就會同時建立一個棧幀,用於儲存區域性變數和運算元棧。每一個方法呼叫到執行完畢就對應著棧楨在棧區入棧到出棧的過程。
4. 本地方法棧:本地方法執行的時候,進入本地方法棧。
5. 方法區:和堆區一樣,都是執行緒共享。

存放JVM載入的型別資訊,如型別基本資訊,常量,方法表等等。

GC機制

GC是java中的垃圾收集器,也是不同於C++的一個地方。C++程式設計人員容易因為忘記或者錯誤地回收記憶體而造成程式崩潰,而Java通過GC機制監測物件是否超過作用域,從而達到自動回收記憶體的目的。

GC的常用演算法

GC的依據就是監測物件的“可達”或“不可達”狀態,但為了讓GC適配不同的平臺,所以GC並沒有對如何進行回收作十分嚴格的規定,不同的實現者有不同的演算法。主要有以及下三種:
1. 引用計數法。簡單但速度很慢。缺陷是:不能處理迴圈引用的情況。
2. 停止-複製(stop and copy)。效率低,需要的空間大,優點,不會產生碎片。
3. 標記 - 清除演算法 (mark and sweep)。速度較快,佔用空間少,標記清除後會產生大量的碎片。
綜述:新生代基本採用複製演算法,老年代採用標記整理演算法。cms採用標記清理。

GC分代


1. Young Generation
* Eden Space (any instance enters the runtime memory area through eden)
* S0 Survivor Space (older instances moved from eden to S0)
* S1 Survivor Space (older instances moved from S0 to S1)
2. Old Generation (instances promoted from S1 to tenured)
3. Permanent Generation (contains meta information like class, method detail)
總體來說,就是新生的物件總是放在Young Generation的eden空間裡,而S0和S1存放的是垃圾回收後剩下存活的物件,而Old Generation則存放一些生命週期上的物件。Young Generation在垃圾回收時,物件的儲存順序是優先順序是S0—->S1—->Old Generation,此時Young Generation利用的是上面提到的(stop-copy)演算法,而Old Generation裡的回收演算法則是 (mark and sweep)演算法。

另外還有一種是增量式GC(Incremental GC),這種GC在JVM中通常是由一個或一組程序來實現的,它本身也和使用者程式一樣佔用heap空間,執行時也佔用CPU。

HotSpot JVM增量式GC的實現是採用Train GC演算法,它的基本想法就是:將堆中的所有物件按照建立和使用情況進行分組(分層),將使用頻繁高和具有相關性的物件放在一隊中,隨著程式的執行,不斷對組進行調整。當GC執行時,它總是先回收最老的(最近很少訪問的)的物件,如果整組都為可回收物件,GC將整組回收。這樣,每次GC執行只回收一定比例的不可達物件,保證程式的順暢執行。

兩個最基本的java回收演算法:複製演算法和標記清理演算法
複製演算法:兩個區域A和B,初始物件在A,繼續存活的物件被轉移到B。此為新生代最常用的演算法
標記清理:一塊區域,標記要回收的物件,然後回收,一定會出現碎片,那麼引出標記-整理演算法:多了碎片整理,整理出更大的記憶體放更大的物件

JVM類載入器

一個jvm中預設的classloader有三種類型,Bootstrap ClassLoader、Extension ClassLoader、App ClassLoader,分別各司其職:
Bootstrap ClassLoader 負責載入java基礎類,主要是 %JRE_HOME/lib/ 目錄下的rt.jar、resources.jar、charsets.jar和class等
Extension ClassLoader 負責載入java擴充套件類,主要是 %JRE_HOME/lib/ext 目錄下的jar和class
App ClassLoader 負責載入當前java應用的classpath中的所有類。
利用雙親委託模型來進行載入
JVM在判定兩個class是否相同時,不僅要判斷兩個類名是否相同,而且要判斷是否由同一個類載入器例項載入的