1. 程式人生 > >Java JVM 7:記憶體結構

Java JVM 7:記憶體結構

JVM 一般可以分為 PC 暫存器,JVM 方法棧,本地方法棧,JVM 方法區 以及 JVM 堆,如下圖:

這裡寫圖片描述

PC 暫存器:可以看做是當前執行緒所執行的位元組碼的行號指示器。它屬於每個執行緒所私有的。

JVM 方法棧:由一條條的棧幀組成,每個棧幀又包括了局部變數區,運算元區,等。每個方法在執行的時候就會建立一個棧幀(所以說遞迴會產生大量的棧幀,假如此時又死迴圈了,那麼這裡棧幀過多,就會造成 stackoverflow 棧溢位異常。)它也是執行緒所私有的。

本地方法棧:主要用於支援 java 語言和其他語言(如C語言)的一個互動。

JVM 方法區:儲存 JVM 載入了的 類的資訊,常量,靜態變數等。簡單來說就相當於平常所說的永久代。(實際上肯定有區別,但是對於新手來說可以暫且認為差不多,相等)。這部分割槽域不是執行緒所私有,而是各個執行緒所共享的。

JVM 堆:這裡主要用於儲存物件和陣列等例項。是 Java 最重要的一塊儲存區域,平常所說的堆記憶體,新生代(eden,survivor區域),老年代就是在這個區域中。因此,這裡也是垃圾收集的主要發生的場所。

上面幾個都是 JVM 的規範,但是 JVM 方法區在 JDK7 和 JDK8 的實現有不同,在 JDK7 中是永久代,在 JDK8 中使用 MetaSpace。

對於 MetaSpace,可以參考:Java 8: 從永久代(PermGen)到元空間(Metaspace),簡單來說,會有一些好處,比如說這部分的記憶體大小隻受到本地記憶體的限制,所以就不會出現之前的永久代溢位的問題。

JVM 堆記憶體劃分

對於JVM 的記憶體區域,還有一個經常談論的地方就是 JVM堆,主要分為了新生代和老年代。其中:

新生代又分為了 1 個 Eden 區域和 2 個 Survivor 區域,比例是 8:1:1。這樣的一個劃分主要是因為新生代採用的垃圾回收演算法為複製演算法而導致的。

對於老年代,和新生代的比例預設為 2:1。

對於一些調整的引數這裡羅列總結一下:

-XX: Persize:設定非堆記憶體初始值,預設為1/64。(JDK7的JVM方法區記憶體)

-XX:MaxPersize:設定非堆記憶體最大值,預設為1/4。(JDK7的JVM方法區記憶體)

-Xss:設定每個執行緒佔用堆記憶體大小,現在預設為1M,以前為256K。設定執行緒越小,堆記憶體大小不變,可以創造的執行緒數越多(當然有一個限度)。但是這個值也需要經過嚴格的測試再設定。

-Xms:JVM堆初始分配記憶體。預設為實體記憶體的1/64,當預設堆記憶體的空餘空間小於40%的時候,這個堆記憶體就會自動增長到-Xmx指定的最大堆分配記憶體。

-Xmx :JVM的最大堆分配記憶體。預設為實體記憶體的1/4,當空餘記憶體大於70%的時候,該堆記憶體又會自動減少到-Xms指定的記憶體。

-Xmn:指定新生代的記憶體大小。當堆大小不變的情況下,新生代越大,老生代越小,預設新生代和老年代的比例為1:2,而且這個比例會嚴重影響系統性能,sun推薦為新生代佔整個堆記憶體3/8

-XX:SurvivorRatio:新生代中,又分為eden區域和兩個Survivor區域。預設比例為8:1:1,也就是說,可以用的記憶體為90%。該引數用來設定eden和Survivor的比值,預設為8:1。

-XX:NewRatio:年輕代(包括Eden和兩個Survivor區)與年老代的比值(除去持久代)