一、JVM是什么?
JVM是Java Virtual Machine(Java虛擬機(jī))的縮寫,是通過在實際的計算機(jī)上仿真模擬各種計算機(jī)功能來實現(xiàn)的。由一套字節(jié)碼指令集、一組寄存器、一個棧、一個垃圾回收堆和一個存儲方法域等組成。JVM屏蔽了與操作系統(tǒng)平臺相關(guān)的信息,使得Java程序只需要生成在Java虛擬機(jī)上運(yùn)行的目標(biāo)代碼(字節(jié)碼),就可在多種平臺上不加修改的運(yùn)行,這也是Java能夠“一次編譯,到處運(yùn)行的”原因。
二、JVM內(nèi)存模型圖
三、JVM運(yùn)行數(shù)據(jù)區(qū)詳解
- JVM運(yùn)行數(shù)據(jù)區(qū)分為虛擬機(jī)棧、本地方法棧、程序計數(shù)器、堆區(qū)、元空間(方法區(qū))五部分。其中虛擬機(jī)棧、本地方法棧和程序計數(shù)器屬于線程私有,而堆、元空間屬于線程共享。
- 虛擬機(jī)棧中存儲方法、方法中的局部變量、以及運(yùn)行時數(shù)據(jù),本地方法棧和虛擬機(jī)棧類似,只不過本地方法中棧存儲的是本地方法的一些數(shù)據(jù)信息,程序計數(shù)器用來表示程序代碼的執(zhí)行位置,每一線程工作時,都會開辟自己的虛擬機(jī)棧、本地方法棧、和程序計數(shù)器。
- 堆區(qū),存儲對象信息,以及數(shù)組,是所有線程共享區(qū)域、
- 元空間存儲類加載的相關(guān)信息,以及靜態(tài)變量、常量、運(yùn)行時常量池等。
下面,以代碼演示各個位置存儲的信息:
//1.首先類加載器將類加載到原空間
public class Application {
//main線程--> main的線程棧,也就是虛擬機(jī)棧
//2.執(zhí)行main 方法,將main方法壓入棧
public static void main(String[] args) throws Exception {
//3.load方法壓入虛擬機(jī)棧
load();
System.in.read(); //保證程序不要退出
}
public static void load() {
//4.在堆區(qū)創(chuàng)建Config對象,同時在棧區(qū)存儲對象的引用地址,指向堆區(qū)
Config config = new Config();
//5.將loadData()方法壓入棧
config.loadData() ;
}
}
public class Config {
//1.靜態(tài)變量存儲在元空間
public static Manager mdnagerl = new Manager();
//2.實例變量/對象變量 和類對象一起存儲在堆區(qū)
private int a;
//3.loadData()存儲在方法區(qū)
public String loadData() {
return "abc";
}
}
四、JVM運(yùn)行數(shù)據(jù)區(qū)各部分特點(diǎn)及作用
-
堆
??堆用來存放對象和數(shù)組,只要是堆中的對象,就可以被所有線程共享(靜態(tài)變量、靜態(tài)常量、字符串存儲在堆中的老年代里)。Java7 版本中將永久代的靜態(tài)變量和運(yùn)行時常量池轉(zhuǎn)移到堆中存放的。
??
??堆是 JVM 上最大的內(nèi)存區(qū)域。垃圾回收操作的對象就是堆。
??
??堆空間一般是程序啟動時就申請了,一般設(shè)置成可伸縮的。 隨著對象的頻繁創(chuàng)建,堆空間占用的越來越多,就需要不定期的對不再使用的對象進(jìn)行回收,這就是GC。
??
?? 對于基本數(shù)據(jù)類型對象(如byte、short、int、long、float、double、char),在方法體內(nèi)聲明時,會直接分配在棧中,其它情況都會分配在堆中。
??
??對于普通對象來說,JVM 會首先在堆上創(chuàng)建對象,然后在其他地方使用它的引用。比如,把這個引用保存在虛擬機(jī)棧的局部變量表中。但是在開啟了逃逸分析時,如果發(fā)現(xiàn)某個對象只會在方法內(nèi)部使用,則可能會將該對象經(jīng)過標(biāo)量替換后也存在棧中。
??
堆的幾個重要參數(shù):
??-Xms:堆的最小值(初始值,默認(rèn)單位是:字節(jié),要求是1024的整數(shù)倍);
??-Xmx:堆的最大值;
??-Xmn:新生代的大??;
??-XX:NewSize;新生代最小值(初始值);
??-XX:MaxNewSize:新生代最大值;
2.虛擬機(jī)棧
?? Java虛擬機(jī)棧是當(dāng)前線程在執(zhí)行方法時存儲所需的數(shù)據(jù)、指令、返回地址的一種棧結(jié)構(gòu)(先進(jìn)后出)。它的生命周期與線程保持一致。提一句:靜態(tài)變量不入棧。
??
?? 每調(diào)用一個方法就會在棧里加入一個棧幀。調(diào)用的方法執(zhí)行完了,對應(yīng)的棧幀就會出棧。棧幀里分為4個區(qū)域,這4個區(qū)域就包含了執(zhí)行Java方法時的全部內(nèi)容。這個4個區(qū)域分別是:局部變量表、操作數(shù)棧、動態(tài)連接、方法出口。
虛擬機(jī)棧默認(rèn)1M。 如果我們不斷的往虛擬機(jī)棧中入棧幀,但是就是不出棧的話,那么這個虛擬機(jī)棧就會溢出。
3.程序計數(shù)器
?? 由于現(xiàn)在都是多線程運(yùn)行,而一個CPU在同一時刻只能運(yùn)行一個線程,多個線程只能交替運(yùn)行。程序計數(shù)器的作用就是記錄當(dāng)前線程下一條要運(yùn)行的指令,這樣保證了線程在切換回來時能回到正確的位置繼續(xù)開始執(zhí)行
?? 程序計算器是唯一不會發(fā)生內(nèi)存溢出的地方。如果正在執(zhí)行的是Native 方法,由于不是JVM執(zhí)行,則這個計數(shù)器值為空(Undefined)文章來源:http://www.zghlxwxcb.cn/news/detail-627097.html
4.方法區(qū)(元空間)
?? 方法區(qū)也是一個線程共享的內(nèi)存區(qū)。
??
?? 方法區(qū)存儲的內(nèi)容有:類型信息(比如類全稱、父類全稱)、域信息(域名稱、域修飾符private等)、方法信息(方法名稱、方法修飾符、返回類型等)、字面量(字面量包括文本字符串、八種基本類型的值 、被聲明為final的常量等)。
??
??假如兩個線程都試圖訪問方法區(qū)中的同一個類信息,而這個類還沒有加載進(jìn) JVM,那么此時就只允許一個線程去加載它,另一個線程必須等待。
??
??方法區(qū)是 JVM 對內(nèi)存的“邏輯劃分”,在 JDK1.7 及之前將方法區(qū)稱為“永久代”,是因為在 HotSpot 虛擬機(jī)中,設(shè)計人員使用了永久代來實現(xiàn)了 JVM 規(guī)范的方法區(qū)。在 JDK1.8 及以后使用了元空間來實現(xiàn)方法區(qū)。
??
??Java8 使用元空間替代永久代,是為了融合 HotSpot JVM 與 JRockit VM ,因為 JRockit 沒有永久代。
??
??元空間大小參數(shù)設(shè)置:
??jdk1.7 及以前:-XX:PermSize;-XX:MaxPermSize;
??jdk1.8 以后:-XX:MetaspaceSize; -XX:MaxMetaspaceSize ;如果不設(shè)置參數(shù),則只受本機(jī)總內(nèi)存的限制文章來源地址http://www.zghlxwxcb.cn/news/detail-627097.html
到了這里,關(guān)于【JVM】JVM內(nèi)存模型詳解的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!