簡介:JVM有很多個不同版本的實現(xiàn);其中HotSpot VM是最主流使用的JVM;Oracle官方j(luò)dk和開源openjdk都是使用這個JVM
JVM內(nèi)存區(qū)域劃分
JVM內(nèi)存區(qū)域劃分:按每個區(qū)域不同功能劃分;相互之間不會干擾
本地方法棧
native:表示是JVM內(nèi)部C++代碼;給調(diào)用JVM內(nèi)部方法準(zhǔn)備的??臻g。存儲本地方法native之間調(diào)用相關(guān)的信息。每個線程都有一份;還會有其它方法參數(shù)、返回地址、局部變量等等很多元素。
程序計數(shù)器
記錄當(dāng)前線程執(zhí)行到哪個指令;每一個線程都有一份
虛擬機棧(和本地方法棧類似)
給java代碼使用的棧;存的是方法之間的調(diào)用關(guān)系;還會有其它方法參數(shù)、返回地址、局部變量等等元素。也是一個線程有一份。
棧幀:每一個方法里對應(yīng)一個棧幀;里面存的這個方法相關(guān)的東西。這里棧幀的空間是連續(xù)的(JVM有參數(shù)可以設(shè)置??臻g大??;超過范圍就會棧溢出;棧溢出指單個的棧幀溢出;死遞歸就非常容易棧溢出)
存活時間:這里的內(nèi)存和方法相關(guān)的;調(diào)用一個方法就會創(chuàng)建棧幀;方法執(zhí)行結(jié)束;棧幀銷毀
棧是私有的嗎?
變量捕獲:也能訪問;所以說棧是私有的是不嚴(yán)謹(jǐn)。應(yīng)該說每個線程有自己私有的棧;而不是是棧是私有的;
堆區(qū)
堆:整個JVM空間最大區(qū)域;new出來的對象都在堆上;類的成員變量也都是在堆上。一個進程只有一份;所有線程共用一個
一個我們上面的原始圖就是一個進程;每一個java進程就是上面的這樣一個JVM
兩個進程為什么不共用一個JVM?
只能說很難辦;那就別辦了。操作系統(tǒng)辦好了;但是不好辦的;而java進程恰好是隔離性做好的;直接用現(xiàn)成的就好了;這樣子不必處理就能有隔離性;讓他們不會互相影響。
元數(shù)據(jù)區(qū)(以前叫方法區(qū))
元:meta;屬性。所以類對象這在這里;注意是類對象;是static?不限于static(方法的字節(jié)碼和運行時數(shù)據(jù)都存在方法區(qū))
類對象:常量池(放在元數(shù)據(jù)區(qū)好處;編譯器確定;不再修改;讓多個對象共享就有利于節(jié)省空間)、靜態(tài)成員
字符串之所以在常量池的好處:這是一種特殊類型;編譯器就確定;而且保持不變;并且可以被多個對象共享;所以放在這里有利于節(jié)省空間
方法區(qū)也是一個線程只有一塊;然后多個線程共用;
public final :可能被編譯器優(yōu)化成字面值常量(就在常量池里);也可能沒有優(yōu)化;看你有沒有加static。
JVM類加載機制
類加載過程
類加載:.class文件從硬盤加載到內(nèi)存(元數(shù)據(jù)區(qū);能在程序運行時快速訪問和使用類的這些信息)過程
加載:找到這個.class文件的過程;打開文件;讀文件內(nèi)容
驗證:檢查.class文件的格式是否符要求;官方規(guī)范文檔上詳細描述.class格式
準(zhǔn)備:給類對象分配內(nèi)存空間(相當(dāng)于先占個位置;內(nèi)存初始化全0)
解析:針對字符串常量進行初始化;把符號轉(zhuǎn)為引用
初始化:針對類對象的內(nèi)容進行初始化內(nèi)存空間;還有加載、執(zhí)行靜態(tài)代碼塊代碼
解析這里把符號轉(zhuǎn)為引用是什么意思呢?
字符串常量,得有一塊內(nèi)存空間,存這個字符的實際內(nèi)容還得有一個引用,來保存這個內(nèi)存空間的起始地址
在類加載之前,字符串常量,此時是處在 .class 文件中的此時這個“引用”記錄的并非是字符串常量的真正的地址;可以認(rèn)為是個占位符。類加載后才把字符串常量放到內(nèi)存中;這時候才有真正的內(nèi)存地址;這個引用才能被真正賦值到正確的內(nèi)存地址
雙親委派模型:描述加載找.class的基本過程
三個類加載器:
1:BootstrapClassLoader負責(zé)加載標(biāo)準(zhǔn)庫中的類((java 規(guī)范要求提供哪些類;無論是哪種JVM 的實現(xiàn)都會提供這些一樣的類)
2:ExtensionClassLoader 負責(zé)加載JVM 擴展庫中的類(不同JVM實現(xiàn)的廠商會做不同擴展一些額外功能)
3:ApplicationClassLoader 負責(zé)加載用戶提供的第三方庫/用戶項目代碼中的類
它們存在一個父子關(guān)系;爺爺、爸爸、孫子。不是繼承那個父子關(guān)系;而相當(dāng)于每一個class loader有一個parent屬性指向自己的父類加載器
類似遞歸邏輯:
首先加載從 ApplicationClassLoader 開始;是 ApplicationClassLoader 會把加載任務(wù)交給父親;而 ExtensionClassLoader 要去加載了;他又委托給自己的父親BootstrapClassLoader 要去加載了。BootstrapClassLoader 也想委托自己的父親結(jié)果發(fā)現(xiàn),自己的父親是 null;沒有父親/父親加載完了,沒找著類,才由自己進行加載。
父類沒找到就讓子類去找;如果到ApplicationClassLoader還沒找到就拋出類找不到的異常
為什么要設(shè)置這個查找順序:
1:假設(shè)用戶自己寫一個java.lang.String類;按這個加載順序不會說加載時候會讓你的類代替人家標(biāo)準(zhǔn)庫的類
2:用戶自定義的類加載器;也可以加入上述流程;跟一個類似鏈表一樣;把自己寫的類加載器掛到它們上面;這樣子類加載可能擴展了
破壞雙親委派模型:
我們不一定要遵循雙親模型;自己寫的類加載器也可以不遵守;看需求是什么;比如Tomcat加載webapp是單獨類加載器;不遵守雙親委派模型文章來源:http://www.zghlxwxcb.cn/news/detail-658404.html
什么時候觸發(fā)類加載呢?
一個類只有真正被用到才加載(懶漢模式);但是加載過后;后續(xù)就不必重復(fù)加載;那么什么時候才算被用到呢?
例如:創(chuàng)建對象、調(diào)用靜態(tài)方法等
你要調(diào)用靜態(tài)屬性;當(dāng)然是要依賴于類對象;new對象跟建房子一樣;你得要有圖紙文章來源地址http://www.zghlxwxcb.cn/news/detail-658404.html
到了這里,關(guān)于JVM內(nèi)存區(qū)域劃分的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!