下圖是完整的虛擬機模型
我們主要是瞭解三個
1. 堆區(heap ):
存儲的全部是對象,每個對象都包含一個與之對應的class的信息。
jvm只有一個堆區(heap)被所有線程共享,堆中不存放基本類型和對象引用,只存放對象本身
2. 棧區(stack):
基本類型變量區、執行環境上下文、操作指令區
每一個線程包含一個stack區,只保存基本數據類型的對象和自定義對象的引用(不是對象),對象都存放在共享堆中;
每個棧中的數據(原始類型和對象引用)都是私有的,其他棧不能訪問。
3. 方法區(meathod area):
又叫靜態區,跟堆一樣,被所有的線程共享。方法區包含所有的class和static變量。
方法區中包含的都是在整個程序中永遠唯一的元素,如class,static變量。
運行時常量池都分配在 Java 虛擬機的方法區之中
另外兩個知道就行了:
本地方法棧(Native Method Stack)
當JVM在執行Native方法時,會在此區域中創建一個棧幀來存放方法的各種信息,比如返回值,局部變量表和各種對象引用等,方法開始執行前就先創建棧幀入棧,執行完後就出棧。
程序計數器(Program Counter Register)
佔用很小的一片區域,我們知道JVM執行代碼是一行一行執行字節碼,所以需要一個計數器來記錄當前執行的行數。
上圖引用的是 '‘斯文流氓騷剛’'的博客圖片
1.1堆詳情圖解
堆裏面分爲年輕代和老年代
年輕代默認佔1/3(Eden默認8/10 , from默認1/10 , to默認 1/10)
老年代默認佔2/3
minor gc :對年輕代的垃圾回收稱作初級回收 , 輕GC
Full GC 是發生在老年代的垃圾收集動作,所採用的是標記-清除算法
(滿了以後自動執行GC , 瞭解GC看我以前博客:
https://blog.csdn.net/qq_42795915/article/details/84202836)
new 的對象先進入Eden 以後經過minor gc計算後放入 from , from 再進行minor gc放入to , 再放入from , 直到對象年齡達到15,若還是有引用對象,再放入老年代
老年代滿了以後會進行一次Full GC的操作 , 如果gc以後還是滿的 , 甚至溢出 , 就會產生堆內存溢出錯誤
舉個堆棧方法區的栗子
public class MainMemory {
int id;
String name;
int size;
Data data;
void store() {
System.out.println("執行存儲中,存儲數據類型:" + data.type);
}
void release() {
System.out.println("釋放內存中");
}
// 構造方法
MainMemory(){
}
public static void main(String [] args) {
MainMemory memory = new MainMemory(); // 創建一個對象
memory.id=1;
memory.name = "test";
memory.size = 1024;
Data data = new Data();
data.type = "字符串";
memory.data = data;
memory.store();
memory.release();
}
}
class Data{
public String type; //這裏不能使用私有類
}
過程:
-
java MainMemory,系統收到指令,啓動一個java虛擬機進程
-
進程首先從classpath中找到MainMemory.class文件,讀取該文件的二進制數據,就是將類信息存放到運行時數據去的方法區中,整個過程是類加載過程,將其加載到方法區中
-
Java虛擬機定位到方法區中MainMemory類的main()方法的字節碼,執行了方法,會分配一個棧幀。
-
創建一個實例對象,也就是在堆區分配一個對象的內存,給對象屬性賦值
-
創建一個Data類對象,先加載該類,然後再分配對象內存,再給該對象賦值
-
調用store()方法,分配棧幀
-
調用release()方法,分配棧幀
圖解:
以上例子來自 '哈K '的博客