java虛擬機在jdk8改變了許多,網(wǎng)絡(luò )上各種解釋都有,在查閱了官方文檔以及一下大佬的解釋以后,我來(lái)粗淺的介紹一下我理解的java8的內存結構。
推薦下自己做的 Spring Boot 的實(shí)戰項目:
https://github.com/YunaiV/ruoyi-vue-pro
推薦下自己做的 Spring Cloud 的實(shí)戰項目:
https://github.com/YunaiV/onemall
Java虛擬機在執行的時(shí)候會(huì )把管理的內存分配成不同的區域,這些區域被稱(chēng)為虛擬機內存,同時(shí),對于虛擬機沒(méi)有直接管理的物理內存,也有一定的利用,這些被利用卻不在虛擬機內存數據區的內存,我們稱(chēng)它為本地內存,這兩種內存有一定的區別:
java虛擬機在執行過(guò)程中會(huì )將所管理的內存劃分為不同的區域,有的隨著(zhù)線(xiàn)程產(chǎn)生和消失,有的隨著(zhù)java進(jìn)程產(chǎn)生和消失,根據《Java虛擬機規范》的規定,運行時(shí)數據區分為以下一個(gè)區域:
程序計數器就是當前線(xiàn)程所執行的字節碼的行號指示器,通過(guò)改變計數器的值,來(lái)選取下一行指令,通過(guò)他來(lái)實(shí)現跳轉、循環(huán)、恢復線(xiàn)程等功能。
線(xiàn)程私有的,每個(gè)線(xiàn)程都已自己的程序計數器。虛擬機棧是線(xiàn)程私有的,隨線(xiàn)程生滅。虛擬機棧描述的是線(xiàn)程中的方法的內存模型:
虛擬機??赡軙?huì )拋出兩種異常:
StackOverFlowError即棧溢出OutOfMemoryError即OOM內存溢出本地方法棧與虛擬機棧的作用是相似的,都會(huì )拋出OutOfMemoryError和StackOverFlowError,都是線(xiàn)程私有的,主要的區別在于:
java堆是JVM內存中最大的一塊,由所有線(xiàn)程共享,是由垃圾收集器管理的內存區域,主要存放對象實(shí)例,當然由于java虛擬機的發(fā)展,堆中也多了許多東西,現在主要有:
string table線(xiàn)程私有,但是不影響java堆的共性java堆既可以是固定大小的,也可以是可擴展的(通過(guò)參數-Xmx和-Xms設定),如果堆無(wú)法擴展或者無(wú)法分配內存時(shí)也會(huì )報OOM
方法區絕對是網(wǎng)上所有關(guān)于java內存結構文章?tīng)幷摰慕裹c(diǎn),因為方法區的實(shí)現在java8做了一次大革新,現在我們來(lái)討論一下:
方法區是所有線(xiàn)程共享的內存,在java8以前是放在JVM內存中的,由永久代實(shí)現,受JVM內存大小參數的限制,在java8中移除了永久代的內容,方法區由元空間(Meta Space)實(shí)現,并直接放到了本地內存中,不受JVM參數的限制(當然,如果物理內存被占滿(mǎn)了,方法區也會(huì )報OOM),并且將原來(lái)放在方法區的字符串常量池和靜態(tài)變量都轉移到了Java堆中,方法區與其他區域不同的地方在于,方法區在編譯期間和類(lèi)加載完成后的內容有少許不同,不過(guò)總的來(lái)說(shuō)分為這兩部分:
版本、字段、方法、接口以及常量池表(Constant Pool Table)常量池表(Constant Pool Table)存儲了類(lèi)在編譯期間生成的字面量、符號引用(什么是字面量?什么是符號引用?),這些信息在類(lèi)加載完后會(huì )被解析到運行時(shí)常量池中直接內存位于本地內存,不屬于JVM內存,但是也會(huì )在物理內存耗盡的時(shí)候報OOM,所以也講一下。
在jdk1.4中加入了NIO(New Input/Putput)類(lèi),引入了一種基于通道(channel)與緩沖區(buffer)的新IO方式,它可以使用native函數直接分配堆外內存,然后通過(guò)存儲在java堆中的DirectByteBuffer對象作為這塊內存的引用進(jìn)行操作,這樣可以在一些場(chǎng)景下大大提高IO性能,避免了在java堆和native堆來(lái)回復制數據。
由于java是一門(mén)高級語(yǔ)言,離硬件底層比較遠,有時(shí)候無(wú)法操作底層的資源,于是,java添加了native關(guān)鍵字,被native關(guān)鍵字修飾的方法可以用其他語(yǔ)言重寫(xiě),這樣,我們就可以寫(xiě)一個(gè)本地方法,然后用C語(yǔ)言重寫(xiě),這樣來(lái)操作底層資源。當然,使用了native方法會(huì )導致系統的可移植性不高,這是需要注意的。
final關(guān)鍵字并不影響在內存中的位置,具體位置請參考上一問(wèn)題。
類(lèi)常量池與運行時(shí)常量池都存儲在方法區,而字符串常量池在jdk7時(shí)就已經(jīng)從方法區遷移到了java堆中。
在類(lèi)編譯過(guò)程中,會(huì )把類(lèi)元信息放到方法區,類(lèi)元信息的其中一部分便是類(lèi)常量池,主要存放字面量和符號引用,而字面量的一部分便是文本字符,在類(lèi)加載時(shí)將字面量和符號引用解析為直接引用存儲在運行時(shí)常量池;對于文本字符來(lái)說(shuō),它們會(huì )在解析時(shí)查找字符串常量池,查出這個(gè)文本字符對應的字符串對象的直接引用,將直接引用存儲在運行時(shí)常量池;字符串常量池存儲的是字符串對象的引用,而不是字符串本身。
字面量
int a=1;//這個(gè)1便是字面量
String b="iloveu";//iloveu便是字面量
符號引用
com.test.Quest作為符號引用存到類(lèi)常量池,等類(lèi)加載完后,拿著(zhù)這個(gè)引用去方法區找這個(gè)類(lèi)的內存地址。聯(lián)系客服