【Java】「深入理解Java虛擬機器」學習筆記(2)-記憶體管理
一、執行時資料區
JVM在執行Java程式的時候,將其執行時資料區劃分為若干不同區域。它們的用途和建立及銷燬的時間不同。
1、程式計數器(Program Counter Register)
是一塊很小的記憶體空間。當執行緒執行的是Java方法,它記錄的是當前正在執行的位元組碼指令的地址;當執行緒執行的是Native方法,則它的值為空。
2、虛擬機器棧(Java Virtual Machine Stacks)
它描述的是Java方法執行的記憶體模型:每個方法在執行的時候都會建立一個棧幀,用來儲存變量表、運算元棧、動態連結和方法出口等資訊。每個方法
從呼叫到執行完成的過程就對應著一個棧幀在虛擬機器棧中從入棧到出棧的過程。
3、本地方法棧(Native Method Stack)
顧名思義,它和虛擬機器棧的區別是:它為本地方法的執行提供服務,虛擬機器棧為Java方法的執行提供服務。
Hotspot不區分虛擬機器棧和本地方法棧。
4、堆(Heap)
它是JVM所管理的記憶體中最大的一塊,隨虛擬機器啟動而建立。它唯一的作用就是存放物件例項,幾乎所有的物件例項和陣列都是在堆上分配,所以是GC的主要管理區域。
5、方法區(Method Area)
又稱作非堆(None-Heap),這個稱謂在JConsole等工具中很常見。它用於儲存已經被JVM載入的類資訊、常量、靜態變數以及即時編譯器編譯後的程式碼等。
♣執行時常量池 方法區中除了存放跟類相關的資訊之外,還有一部分是執行時常量池。它用來存放編譯器產生的字面量和符號引用。 int i = 1; //將1賦值給變數i,那麼1就是字面量 String s = "abc"; //字串abc也是字面量 字面量包括整數、浮點數、字串有些語言的字面量還包括布林型。 在編譯時, Java類並不知道所引用的類的實際地址, 因此只能使用符號引用來代替。比如org.simple.People類引用了org.simple.Language類,在編譯時People類並不知道 Language類的實際記憶體地址, 因此只能使用符號org.simple.Language來表示Language類的地址,org.simple.Language就是所謂的符號引用 執行時常量池的作用是節省空間和時間。例如字串常量池,在編譯階段就把所有的字串放到一個常量池中,可以避免頻繁的建立和銷燬物件而影響系統性能,同時實現了物件的共享。 |
二、物件的建立
物件的建立一般是在new、物件克隆和反序列化的時候。
三、物件的記憶體佈局
四、物件的訪問定位
一般地,物件的訪問定位方式有兩種:通過控制代碼訪問和通過直接指標訪問。
JVM在呼叫一個方法的時候,會在虛擬機器棧上建立棧幀,其本地變量表中會包含物件的reference。
1、通過控制代碼訪問:
在堆上劃出一部分作為物件控制代碼池,控制代碼中包含兩個指標—物件例項資料指標和物件型別資料指標。reference用控制代碼作為跳板,來訪問物件的例項資料(堆上)
和物件型別資料(方法區裡)。
2、通過直接指標訪問:
堆上不單獨劃控制代碼池,在給物件分配的記憶體中包含物件例項資料和型別資料指標。通過reference直接訪問物件例項資料,通過型別資料指標作為跳板來訪問
方法區中的物件型別資料。Hotspot使用這種方法。
五、記憶體溢位
1、堆溢位
堆溢位會報錯java.lang.OutOfMemoryError。
首先要區分是洩露還是溢位,洩露一般是由於某些原因導致物件脫離了GC的管理。如果是溢位,可以考慮優化虛擬機器的堆引數(Xms和Xmx)。
可以通過記憶體對映分析工具Eclipse Memory Analyzer進行分析,找到解決方案。
2、虛擬機器和本地方法棧溢位
原因有兩個:①執行緒請求棧深度超過虛擬機器允許的最大值,會報錯java.lang.StackOverFlow;
②棧空間的額度給的太小,會報錯java.lang.OutOfMemoryError。
3、方法區和執行時常量池
原因是執行時載入了大量的類資訊填滿了方法區導致溢位,會報錯java.lang.OutOfMemoryError。
【參考文章】
https://blog.csdn.net/BraveLoser/article/details/82500474
https://blog.csdn.net/BraveLoser/article/details/82500474