基礎知識之jvm記憶體空間
Java基礎知識之jvm記憶體空間
1 JVM記憶體空間有哪些分割槽?
- 堆
- 方法區
- JAVA虛擬機器棧
- 程式計數器
- 本地方法棧
-
堆空間(HEAP):是建立物件的例項和陣列都存放的記憶體空間,是隨著虛擬機器的啟動而建立的,它是執行緒共享的區域,所以操作共享區域的成員就有了鎖和同步。一個jvm只擁有一個這樣的空間,同時它是gc的主要回收區。它分為三個部分:新生代、老生代、永久代。如果再細緻一點,Java Heap的新生代還有Eden空間,From Survivor空間,To Survivor空間。Java Heap可以處於物理上不連續的記憶體空間中,只要邏輯上是連續的即可。如下圖所示。
新生代是類的誕生、成長、消亡的區域,大部分類在這裡產生,應用,最後被垃圾回收器收集,結束生命。新生代又分為兩部分:伊甸園(Eden space)和倖存者區(Survivor pace),所有的類都是在伊甸園被new出來的。倖存區有兩個為什麼要用兩個?
:0區(Survivor 0 space)和1區(Survivor 1 space)。當伊甸園的空間用完時,程式又需要建立物件,JVM的垃圾回收器將對伊甸園進行垃圾回收(Minor GC),將伊甸園中的剩餘物件移動到倖存0區。若倖存0區也滿了,再對該區進行垃圾回收,然後移動到1區。那如果1去也滿了就放入0區。預設迭代15次後物件移動到老年代。若養老區也滿了,那麼這個時候將產生Major GC(FullGCC),進行養老代的記憶體清理。若養老代執行Full GC 之後發現依然無法進行物件的儲存,就會產生OOM異常“OutOfMemoryError”。
如果出現java.lang.OutOfMemoryError: Java heap space異常,說明Java虛擬機器的堆記憶體不夠。原因有:
a.Java虛擬機器的堆記憶體設定不夠,可以通過引數-Xms、-Xmx來調整。
b.程式碼中建立了大量大物件,並且長時間不能被垃圾收集器收集(存在被引用)。
② 養老代
養老代用於儲存從新生代篩選出來的 JAVA 物件,一般池物件都在這個區域活躍。
③ 永久代
永久代是一個常駐記憶體區域,用於存放JDK自身所攜帶的 Class,Interface 的元資料,也就是說它儲存的是執行環境必須的類資訊,被裝載進此區域的資料是不會被垃圾回收器回收掉的,關閉 JVM 才會釋放此區域所佔用的記憶體。
如果出現java.lang.OutOfMemoryError: PermGen space,說明是Java虛擬機器對永久代Perm記憶體設定不夠。原因:
a. 程式啟動需要載入大量的第三方jar包。例如:在一個Tomcat下部署了太多的應用。
b. 大量動態反射生成的類不斷被載入,最終導致Perm區被佔滿。
說明:
Jdk1.6及之前:常量池分配在永久代 。
Jdk1.7:有,但已經逐步“去永久代” 。
Jdk1.8及之後:無(java.lang.OutOfMemoryError: PermGen space,這種錯誤將不會出現在JDK1.8中)。
-
方法區(Method Area):是各個執行緒共享的記憶體區域,它用於儲存虛擬機器載入的類資訊,常量,靜態變數,即時編譯器編譯後的程式碼等資料。常量池:(Constant Pool)是方法區的一部分,Class檔案除了有類的版本、欄位、方法、介面等描述資訊外,還有一項資訊就是常量池,這部分內容將在類載入後進入方法區的執行時常量池中存放。
靜態變數+常量+類資訊+執行時常量池存在方法區中,例項變數存在堆記憶體中。
-
JVM虛擬機器棧(Stack):它是執行緒安全的,它的生命週期和執行緒一樣。它描述的是一個java方法執行記憶體模型。每個方法執行過程鍾都會建立一個棧幀(Frame)用來儲存區域性變量表、運算元棧、動態連結、方法出口。每個執行緒在執行一個方法時,都意味了有一個當前棧幀在進棧和出棧。區域性變量表存放了編譯時期的各種基本資料型別,物件引用。
-
本地方法棧(Native Stack):與Java虛擬機器站(Java Stack)所發揮的作用非常相似,他們之間的區別在於虛擬機器棧為虛擬機器棧執行java方法(也就是位元組碼)服務,而本地方法棧則為使用到Native方法服務。
-
程式計數器(PC):指令執行的順序就是PC暫存器在管,它的作用就是控制程式指令的執行順序。
總結
- 執行緒私有的資料區域有:
Java虛擬機器棧(Java Stack)
本地方法棧(Native Stack)
程式計數器 - 執行緒共有的資料區域有:
堆(Java Heap)
方法區