JVM內存模型
image-20230225234803065
fbad0ab70d80cd753d625ef615f94d2
類加載器子系統負責從文件系統或者網絡中加載class文件到我們的JVM的內存中去,class文件在文件開頭有特定的文件標識。加載的類信息存放於方法區。
字節碼執行引擎是具體執行我們代碼的。
本地方法棧在執行native方法時候會在本地方法棧中創建內存。
創建對象具體存放在堆中,局部變量表中只是保存著堆的引用。
方法區存放方法,類元信息,靜態變量。
每個線程都會分配一個線程棧。
線程棧對應一個自己的程序計數器,程序計數器是由字節碼執行引擎每次執行一行代碼都會修改程序計數器。
在線程中執行方法,會創建方法自己的棧幀,遵循先進後出。
方法出口保留上一個方法的執行代碼行數,當方法執行完成,棧幀釋放,通過方法出口回到上一個方法,繼續執行。
main方法執行在JVM的操作流程
public static void main(String[] args) {
Test Test = new Test();
test.calculate();
}
public void calculate() {
int a = 5;
int b = 10;
int c = a + b;
}
image-20230226093117700
1:首先將java編譯成class文件。
2:類加載子系統將class文件加載到JVM虛擬機中。
3:字節碼執行引擎執行代碼。
4:在棧中創建線程,開始準備執行main方法。
5:在main線程棧中創建main方法的棧幀,棧幀是獨立的,棧幀中的局部變量表也是獨立的,當方法執行結束自動釋放棧幀。
6:開始new對象。
先在棧幀中局部變量表中開闢一個內存空間
在堆中開闢內存空間
在堆中創建實例
堆中的實例指向棧幀中新開闢的內存,進行關聯
7:執行方法。由於calculate方法不是靜態方法,所以應該先將符號引用轉變為新new出來對象的直接引用,動態解析。並且把main棧正的代碼行數記錄到calculate的方法出口裡,當方法執行結束,就繼續執行main方法。
8:在main線程棧中創建棧幀calculate。
9:執行 int a = 5,在calculate棧幀的局部變量表中開闢a的內存空間
10:將5壓入操作樹棧中。
11:將5從操作樹棧中移除並賦值給局部變量表中的a
12:int b同理
13:執行加操作,將a的值加載到操作數棧,將b的值加載到操作數棧
14:將操作數棧的值拿到cpu中進行加操作,執行完成放回操作數棧
15:將操作數棧的值移除並賦值給局部變量表中的c
16:執行方法出口,calculate棧幀釋放
17:main方法棧幀執行完成,釋放
18:main線程結束
從JDK源碼級別剖析JVM類加載機制
JVM內存參數設置
java ‐Xms2048M ‐Xmx2048M ‐Xmn1024M ‐Xss512K ‐XX:MetaspaceSize=256M ‐XX:MaxMetaspaceSize=256M ‐jar microservice‐eureka‐server.jar
-XX:MaxMetaspaceSize:設置元空間的最大值,默認-1,不受到限制,只限制於我們內存大小
‐XX:MetaspaceSize:元空間觸發FULL GC的閾值,默認21M,當達到閾值的時候,觸發FULL GC,同時收集器會對該值進行調整: 如果釋放了大量的空間, 就適當降低該值; 如果釋放了很少的空間,那麼在不超
過該值情況下,適當提高該值,如果我們在啟動項目的時候一卡一卡的,可能存在元空間full gc,適當調大元空間大小。
image-20230226100513013