Java學(xué)習(xí)Java虛擬機(jī)(JVM)原理

      網(wǎng)友投稿 778 2022-05-30

      一、Java虛擬機(jī)工作原理

      首先Java源文件經(jīng)過前端編譯器(javac或ECJ)將.java文件編譯為Java字節(jié)碼文件,然后JRE加載Java字節(jié)碼文件,載入系統(tǒng)分配給JVM的內(nèi)存區(qū),然后執(zhí)行引擎解釋或編譯類文件,再由即時(shí)編譯器將字節(jié)碼轉(zhuǎn)化為機(jī)器碼。

      (1)類加載

      類加載指將類的字節(jié)碼文件(.class)中的二進(jìn)制數(shù)據(jù)讀入內(nèi)存,將其放在運(yùn)行時(shí)數(shù)據(jù)區(qū)的方法區(qū)內(nèi),然后在堆上創(chuàng)建java.lang.Class對(duì)象,封裝類在方法區(qū)內(nèi)的數(shù)據(jù)結(jié)構(gòu)。類加載的最終產(chǎn)品是位于堆中的類對(duì)象,類對(duì)象封裝了類在方法區(qū)內(nèi)的數(shù)據(jù)結(jié)構(gòu),并且向JAVA程序提供了訪問方法區(qū)內(nèi)數(shù)據(jù)結(jié)構(gòu)的接口。

      Java學(xué)習(xí)之Java虛擬機(jī)(JVM)原理

      啟動(dòng)類加載器(BootstrapClassLoader):在JVM運(yùn)行時(shí)被創(chuàng)建,負(fù)責(zé)加載存放在JDK安裝目錄下的jre\lib的類文件,或者被-Xbootclasspath參數(shù)指定的路徑中,并且能被虛擬機(jī)識(shí)別的類庫(如rt.jar,所有的java.*開頭的類均被Bootstrap ClassLoader加載)。啟動(dòng)類無法被JAVA程序直接引用。

      擴(kuò)展類加載器(Extension ClassLoader):該類加載器負(fù)責(zé)加載JDK安裝目錄下的\jre\lib\ext的類,或者由java.ext.dirs系統(tǒng)變量指定路徑中的所有類庫,開發(fā)者也可以直接使用擴(kuò)展類加載器。

      應(yīng)用程序類加載器(AppClassLoader):負(fù)責(zé)加載用戶類路徑(Classpath)所指定的類,開發(fā)者可以直接使用該類加載器,如果應(yīng)用程序中沒有定義過自己的類加載器,該類加載器為默認(rèn)的類加載器。

      用戶自定義類加載器(User ClassLoader):JVM自帶的類加載器是從本地文件系統(tǒng)加載標(biāo)準(zhǔn)的java class文件,而自定義的類加載器可以做到在執(zhí)行非置信代碼之前,自動(dòng)驗(yàn)證數(shù)字簽名,動(dòng)態(tài)地創(chuàng)建符合用戶特定需要的定制化構(gòu)建類,從特定的場(chǎng)所(數(shù)據(jù)庫、網(wǎng)絡(luò)中)取得java class。

      注意如上的類加載器并不是通過繼承的方式實(shí)現(xiàn)的,而是通過組合的方式實(shí)現(xiàn)的。而JAVA虛擬機(jī)的加載模式是一種委派模式,如上圖中的1-7步所示。下層的加載器能夠看到上層加載器中的類,反之則不行。類加載器可以加載類但是不能卸載類。

      (2)運(yùn)行時(shí)數(shù)據(jù)區(qū)

      運(yùn)行時(shí)數(shù)據(jù)區(qū)分為方法區(qū)、Java堆、虛擬機(jī)棧、本地方法棧、程序計(jì)數(shù)器。其中方法區(qū)和Java堆一樣,是各個(gè)線程共享的內(nèi)存區(qū)域,而虛擬機(jī)棧、本地方法棧、程序計(jì)數(shù)器是線程私有的內(nèi)存區(qū)。

      程序計(jì)數(shù)器:線程私有的,他是一塊較小的內(nèi)存空間,他相當(dāng)字節(jié)碼于解釋器中的指針,也就是該內(nèi)存存放下一條即將執(zhí)行指令的地址。字節(jié)碼解釋器就是通過改變 這個(gè)計(jì)數(shù)器的值來選擇下一條即將執(zhí)行的指令。每一個(gè)線程都有一個(gè)程序計(jì)數(shù)器(內(nèi)存),這樣線程切換的時(shí)候就能找到自己各個(gè)線程各自即將執(zhí)行的下一條指令。 所以說是線程私有的。

      Java虛擬機(jī)棧:線程私有的,每一個(gè)方法在執(zhí)行的時(shí)候就會(huì)創(chuàng)建一個(gè)棧幀來存放方法的局部變量,操作數(shù)棧,返回地址等,當(dāng)方法執(zhí)行完成的時(shí)候就釋放該棧幀。?棧幀:虛擬機(jī)棧中是一棧幀為單位存儲(chǔ)的,所以一個(gè)虛擬機(jī)棧中有很多棧幀,每一個(gè)棧幀中分為:局部變量區(qū)(存放方法的參數(shù)和局部變量),操作數(shù)棧,方法的返回地址,動(dòng)態(tài)鏈接(一般解析解階段是將部分符號(hào)引用轉(zhuǎn)換成直接應(yīng)用(類加載),而動(dòng)態(tài)鏈接是另外一部分的符號(hào)引用轉(zhuǎn)換成直接引用(運(yùn)行時(shí)))

      本地虛擬機(jī)棧:線程私有,本地方法指的是那種不是用java語言寫的方法,java虛擬機(jī)棧只針java方法,而不是本地方法。hotspot虛擬機(jī)支持別的語言寫的方法在虛擬機(jī)上運(yùn)行,本法方法棧和java虛擬機(jī)棧一樣。只是他們服務(wù)的對(duì)象不一樣而已,一個(gè)為java方法服務(wù),一個(gè)為native方法服務(wù)。

      Java堆:線程共享的,不過也可能為多個(gè)線程分配私有的buffer,也就是每個(gè)線程有自己的緩存器,java堆可以是物理上連續(xù)的,也可以是不連續(xù)的。java堆是垃圾回收器管理的主要區(qū)域,所以也叫g(shù)c堆。java堆可以分為:新生代和老年代

      方法區(qū):線程共享的,可以理解為gcc中所所說的靜態(tài)區(qū),不過也不是確切的準(zhǔn)確,因?yàn)樵趆otspot虛擬機(jī)中他存放的是類中靜態(tài)變量和常量(注意是常量哦)。因?yàn)樗艽鎯?chǔ)常量,所以還有存儲(chǔ)常量的區(qū)域有一個(gè)特別的名稱,叫做常量池(包括引用和基本數(shù)據(jù)類型的常量),方法區(qū)并不是堆,這一點(diǎn)和靜態(tài)區(qū)很相似。所以別名叫non-heap,java堆中可以選擇不實(shí)現(xiàn)gc回收,但是實(shí)際上呢還是會(huì)的,只能說垃圾回收器在這個(gè)區(qū)域不活躍而已,但是回收都是回收常量池中的常量,而不是靜態(tài)變量。可以稱為永久代。

      運(yùn)行時(shí)常量池:它是方法區(qū)的一部分,但是和方法區(qū)的常量池有區(qū)別,他存放的常量是在運(yùn)行時(shí)產(chǎn)生的,而不是編譯時(shí)產(chǎn)生的。注意與普通方法區(qū)的區(qū)別

      (3)字節(jié)碼的加載是第一步,其后分別是認(rèn)證、準(zhǔn)備、解析、初始化。

      加載:加載有兩種情況,①當(dāng)遇到new關(guān)鍵字,或者static關(guān)鍵字的時(shí)候就會(huì)發(fā)生(他們對(duì)應(yīng)著對(duì)應(yīng)的指令)如果在常量池中找不到對(duì)應(yīng)符號(hào)引用時(shí),就會(huì)發(fā)生加載 ,②動(dòng)態(tài)加載,當(dāng)用反射方法(如class.forName(“類名”)),如果發(fā)現(xiàn)沒有初始化,則要進(jìn)行初始化。(注:加載的時(shí)候發(fā)現(xiàn)父類沒有被加載,則要先加載父類)

      驗(yàn)證:這一階段的目的是確保class文件的字節(jié)流中包含的信息符合當(dāng)前虛擬機(jī)的要求,并不會(huì)危害虛擬機(jī)自身的安全(雖然編譯器會(huì)嚴(yán)格的檢查java代碼并生成class文件,但是class文件不一定都是通過編譯器編譯,然后加載進(jìn)來的,因?yàn)樘摂M機(jī)獲取class文件字節(jié)流的方式有可能是從網(wǎng)絡(luò)上來的,者難免不會(huì)存在有人惡意修改而造成系統(tǒng)崩潰的問題,class文件其實(shí)也可以手寫16進(jìn)制,因此這是必要的)

      準(zhǔn)備:該階段就是為對(duì)象分派內(nèi)存空間,然后初始化類中的屬性變量,但是該初始化只是按照系統(tǒng)的意愿進(jìn)行初始化,也就是初始化時(shí)都為0或者為null。因此該階段的初始化和我們常說初始化階段的初始化時(shí)不一樣的

      解析:解析就是虛擬機(jī)將常量池中的符號(hào)引用替換成直接引用的過程。符號(hào)引用其實(shí)就是class文件常量池中的各種引用,他們按照一定規(guī)律指向了對(duì)應(yīng)的類名,或者字段,但是并沒有在內(nèi)存中分配空間,因此符號(hào)因此就理解為一個(gè)標(biāo)示,而在直接引用直接指向內(nèi)存中的地址

      初始化:簡(jiǎn)單講就是執(zhí)行對(duì)象的構(gòu)造函數(shù),給類的靜態(tài)字段按照程序的意愿進(jìn)行初始化,注意初始化的順序。(此處的初始化由兩個(gè)函數(shù)完成,一個(gè)是,初始化所有的類變量(靜態(tài)變量),該函數(shù)不會(huì)初始化父類變量,還有一個(gè)是實(shí)例初始化函數(shù),對(duì)類中實(shí)例對(duì)象進(jìn)行初始化,此時(shí)要如果有需要,是要初始化父類的)

      Java JVM 虛擬化

      版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實(shí)的內(nèi)容,請(qǐng)聯(lián)系我們jiasou666@gmail.com 處理,核實(shí)后本網(wǎng)站將在24小時(shí)內(nèi)刪除侵權(quán)內(nèi)容。

      上一篇:【免費(fèi)報(bào)名直播】連街坊小攤都開啟了掃碼支付,你還不懂開發(fā)?
      下一篇:Pycharm最全常用快捷鍵總結(jié)
      相關(guān)文章
      亚洲视频精品在线观看| 久久久久亚洲av无码专区| 亚洲国产精品成人精品小说| 久久亚洲一区二区| 亚洲日韩国产精品第一页一区| 亚洲午夜福利精品无码| 亚洲午夜无码片在线观看影院猛 | 亚洲精品国产免费| 亚洲天堂一区二区| 老汉色老汉首页a亚洲| 91久久亚洲国产成人精品性色 | 亚洲综合无码一区二区三区| 亚洲精品在线网站| 亚洲精品偷拍无码不卡av| 亚洲色欲www综合网| 亚洲精品在线播放| 亚洲午夜精品一区二区公牛电影院| 亚洲小说图片视频| 国产成人精品日本亚洲18图| 亚洲欧美成aⅴ人在线观看| 亚洲爆乳少妇无码激情| 日日摸日日碰夜夜爽亚洲| 亚洲国产精品一区二区三区久久| 亚洲无码黄色网址| 亚洲日韩国产精品第一页一区| 久久精品国产精品亚洲艾草网| 亚洲国产人成网站在线电影动漫| 亚洲欧洲日产国产综合网| 亚洲美女视频网站| 亚洲日本久久久午夜精品| 亚洲AV无码专区亚洲AV桃| 亚洲成A人片在线观看中文| 亚洲午夜福利在线观看| 亚洲av永久无码制服河南实里| 亚洲综合自拍成人| 亚洲一区在线观看视频| 亚洲精品国产首次亮相| 亚洲国产av无码精品| 亚洲日韩精品射精日| 亚洲人成在线影院| 亚洲1234区乱码|