學(xué)習(xí)筆記20170601">【PMP】學(xué)習(xí)筆記20170601
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)的接口。
啟動(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)容。