一、java內存區域:
1、程序計數器(線程私有):
內存中較小的內存空間,可以當做當前線程所執行字節碼的行號指示器。如分支、循環、跳轉、異常處理、線程恢復都需要依賴這個計數器完成。
2、java虛擬機棧(線程私有):
也就是我們通常所說的“堆棧”中的棧。棧是由一個個棧幀組成的。棧幀中存放局部變量表、各種基本的數據類型(boolean、byte、char、short、int、float、long、double)、對象引用、方法返回地址等。當線程執行一個方法時,就會隨之創建一個對應的棧幀,並將建立的棧幀壓棧。當方法執行完畢之後,便會將棧幀出棧。所以遞歸調用容易出現StackOverflowError異常,即線程請求的棧深度超過了虛擬機允許的最大深度。
每個線程分配的棧的大小是設置的(-Xss來設置),棧的基本單位是棧幀。所以棧幀所佔空間越大,棧的深度就越小,反之亦然。簡單的可以理解爲:棧的大小=棧幀大小平均值*棧的深度。
3、本地方法棧(線程私有):
與虛擬機棧發揮的作用類似,只不過本地方法棧使用的本地方法服務(Native方法服務)。
4、java堆(所有線程共享):
在虛擬機啓動時創建,存放對象的實例。
從GC回收的角度來說,可細分爲新生代、老年代。
更細緻的把新生代拆分爲Eden空間、From Survivor空間、To Survivor空間等。
可以通過-Xms和-Xmx控制分配的堆的大小。當堆內沒有足夠的內存完成實例分配,且到達堆的大小上限,會拋出OutOfMemoryError異常,即我們經常說的OOM。
5、方法區(所有線程共享):
存放已被虛擬機加載的類的信息、常量池、靜態變量、即時編譯器編譯後的代碼(JIT)、64位系統上類壓縮指針等數據。
邏輯上雖爲java虛擬機堆的一部分,爲了和java堆區分開來,又稱爲Non-Heap(非堆)。
在jdk1.8之前方法區通過“永久代”(PermGen)來實現,在jdk1.8及以後廢棄,採用“元空間”(MetaSpace)來實現。最大的區別是永久代是在jvm虛擬機上分配的內存,而元空間是分配的本地內存。可通過-XX:MetaspaceSize和-XX:MaxMetaspaceSize配置元空間分配的大小和上限。
更細緻的拆分MetaSpace(元空間)、CodeCache(代碼緩存區,主要存放JIT編譯生成的二進制代碼)、CompressedClassPointSpace(壓縮類指針空間,主要用於64位系統上類壓縮指針)。
二、總結:
整理下,輸出個思維導圖。
參考資料:
《深入理解JAVA虛擬機》