Java JVM原理與調(diào)優(yōu)_動力節(jié)點(diǎn)Java學(xué)院整理
JVM是一種用于計(jì)算設(shè)備的規(guī)范,它是一個(gè)虛構(gòu)出來的計(jì)算機(jī),是通過在實(shí)際的計(jì)算機(jī)上仿真模擬各種計(jì)算機(jī)功能來實(shí)現(xiàn)的。Java虛擬機(jī)包括一套字節(jié)碼指令集、一組寄存器、一個(gè)棧、一個(gè)垃圾回收堆和一個(gè)存儲方法域。 JVM屏蔽了與具體操作系統(tǒng)平臺相關(guān)的信息,使Java程序只需生成在Java虛擬機(jī)上運(yùn)行的目標(biāo)代碼(字節(jié)碼),就可以在多種平臺上不加修改地運(yùn)行。是運(yùn)行Java應(yīng)用最底層部分。
JDK(Java Development kit)
整個(gè)Java的核心,包括了Java運(yùn)行環(huán)境(Java Runtime Envirnment),一堆Java工具(編譯,debug等)和Java基礎(chǔ)的類庫(rt.jar)。是開發(fā)java應(yīng)用的基礎(chǔ)。
JRE(Java Runtime Environment,Java運(yùn)行環(huán)境)
運(yùn)行JAVA程序所必須的環(huán)境的集合,包含JVM標(biāo)準(zhǔn)實(shí)現(xiàn)及Java核心類庫。運(yùn)行java應(yīng)用的基礎(chǔ)。
J2SE(Java 2 Platform,Standard Edition)。
包含那些構(gòu)成Java語言核心的類。比如:數(shù)據(jù)庫連接、接口定義、輸入/輸出、網(wǎng)絡(luò)編程
J2EE(Java 2 Platform,Enterprise Edition)。
Enterprise Edition(企業(yè)版) J2EE 包含J2SE 中的類,并且還包含用于開發(fā)企業(yè)級應(yīng)用的類。比如:EJB、servlet、JSP、XML、事務(wù)控制。
主要JVM
首先,JVM是一套規(guī)范。很多公司均實(shí)現(xiàn)了各自的虛擬機(jī)。常見的有
HotSpot JVM(sun)
Jrockit JVM(BEA公司的JVM,應(yīng)用于weblogic)
IBM JVM
Apache Harmony
其中,我們常用的是HotSpot JVM.
JVM結(jié)構(gòu)
第一步(編譯):
創(chuàng)建完源文件之后,程序會先被編譯為.class文件。Java編譯一個(gè)類時(shí),如果這個(gè)類所依賴的類還沒有被編譯,編譯器就會先編譯這個(gè)被依賴的類,然后 引用,這個(gè)有點(diǎn)象make。如果java編譯器在指定目錄下找不到該類所其依賴的類的.class文件或者.java源文件的話,編譯器話 報(bào)“cant find symbol”的錯(cuò)誤。
第二步(運(yùn)行):
Java類運(yùn)行的過程大概可分為兩個(gè)過程:1、類的加載 2、類的執(zhí)行。
需要說明的是:JVM主要在程序第一次主動使用類的時(shí)候,才會去加載該類。也就是說,JVM并不是在一開始就把一個(gè)程序就所有的類都加載到內(nèi)存中,而是到不得不用的時(shí)候才把它加載進(jìn)來,而且只加載一次。
1、 在 編譯好java程序得到MainApp.class文件后,在命令行上敲java AppMain。系統(tǒng)就會啟動一個(gè)jvm進(jìn)程,jvm進(jìn)程從classpath路徑中找到一個(gè)名為AppMain.class的二進(jìn)制文件,將 MainApp的類信息加載到運(yùn)行時(shí)數(shù)據(jù)區(qū)的方法區(qū)內(nèi),這個(gè)過程叫做MainApp類的加載。
2、 (java命令)然后JVM找到AppMain的主函數(shù)入口,開始執(zhí)行main函數(shù)
3、 (類加載器)執(zhí)行過程中,會創(chuàng)建對象。JVM會首先從方法區(qū)加載類信息和相關(guān)常量,class加載完畢之后,在堆上為對象分配內(nèi)存,然后調(diào)用初始化實(shí)例,當(dāng)然這時(shí)候?qū)嵗3种赶騝lass類型信息,這個(gè)信息保存在方法區(qū)中。
4、 (執(zhí)行引擎)調(diào)用實(shí)例方法時(shí),會根據(jù)引用找到對象信息,進(jìn)而可定位對應(yīng)的class類型信息,和方法表。
5、 (執(zhí)行引擎)執(zhí)行方法時(shí),在虛擬機(jī)棧中進(jìn)行,分配棧幀,隨著入棧出棧,完成方法調(diào)用操作。
執(zhí)行引擎
運(yùn)行Java的每一個(gè)線程都是一個(gè)獨(dú)立的虛擬機(jī)執(zhí)行引擎的實(shí)例。從線程生命周期的開始到結(jié)束,他要么在執(zhí)行字節(jié)碼,要么在執(zhí)行本地方法。一個(gè)線程可能通過解釋或者使用芯片級指令直接執(zhí)行字節(jié)碼,或者間接通過JIT執(zhí)行編譯過的本地代碼。我們上文講到的main函數(shù),也就是執(zhí)行引擎的操作入口。
Class文件
實(shí)際上,Class文件中方法的字節(jié)碼流就是有JVM的指令序列構(gòu)成的。每一條指令包含一個(gè)單字節(jié)的操作碼,后面跟隨0個(gè)或多個(gè)操作數(shù)。
iload_0 // 把存儲在局部變量區(qū)中索引為0的整數(shù)壓入操作數(shù)棧。
iload_1 // 把存儲在局部變量區(qū)中索引為1的整數(shù)壓入操作數(shù)棧。
iadd // 從操作數(shù)棧中彈出兩個(gè)整數(shù)相加,在將結(jié)果壓入操作數(shù)棧。
istore_2 // 從操作數(shù)棧中彈出結(jié)果
JVM運(yùn)行時(shí)數(shù)據(jù)區(qū)
1)程序計(jì)數(shù)器(線程私有)
當(dāng)前線程所執(zhí)行的字節(jié)碼的行號指示器,通過改變這個(gè)計(jì)數(shù)器的值,確定下一條要執(zhí)行的命令。分支,循環(huán),跳轉(zhuǎn)都需要它的支持。
它是線程私有的,每個(gè)線程都有專屬于自己的程序記數(shù)器,線程之間互不影響,獨(dú)立存儲,保證了線程切換后,可以恢復(fù)到原先執(zhí)行位置。
2)Java虛擬機(jī)棧(線程私有)
每個(gè)方法的執(zhí)行,同時(shí)都會在虛擬機(jī)棧上創(chuàng)建一個(gè)棧幀。用于存儲局部變量表,操作數(shù)棧,方法出口,動態(tài)鏈接等。一個(gè)方法的執(zhí)行周期,同時(shí)也就對應(yīng)著棧幀的出棧入棧操作。有時(shí)候方法的遞歸,會造成大量的棧幀,達(dá)到一定的深度,會報(bào)StackOverflowError異常。有一點(diǎn)需要說明:在編譯器編譯Java代碼時(shí),就已經(jīng)在字節(jié)碼中為每個(gè)方法都設(shè)置好了局部變量區(qū)和操作數(shù)棧的數(shù)據(jù)和大小。并在JVM首次加載方法所屬的Class文件時(shí), 就將這些數(shù)據(jù)放進(jìn)了方法區(qū)。因此在線程調(diào)用方法時(shí),只需要根據(jù)方法區(qū)中的局部變量區(qū)和操作數(shù)棧的大小來分配一個(gè)新的棧幀的內(nèi)存大小,并堆入Java棧。
局部變量區(qū): 用來存放方法中的所有局部變量值,包括傳遞的參數(shù)。這些數(shù)據(jù)會被組織成以一個(gè)字長(32bit或64bit)為單位的數(shù)組結(jié)構(gòu)(以索引0開始)中。其中類 型為int, float, reference(引用類型,記錄對象在堆中地址)和returnAddress(一種JVM內(nèi)部使用的基本類型)的值占用1個(gè)字長,而byte, char和shot會擴(kuò)大成1個(gè)字長存儲,long,double則使用2個(gè)字長。
操作數(shù)棧: 用來在執(zhí)行指令的時(shí)候存儲和使用中間結(jié)果數(shù)據(jù)。
幀數(shù)據(jù)區(qū): 常量池的解析,正常方法返回以及異常派發(fā)機(jī)制的信息數(shù)據(jù)都存儲在其中。
3)本地方法棧(線程私有)
與Java虛擬機(jī)棧類似,只不過該區(qū)域是為native方法提供服務(wù)。
4)方法區(qū)(Perm)(線程共享)
存儲已被虛擬機(jī)加載的類信息,常量,靜態(tài)變量,即時(shí)編譯后的代碼等數(shù)據(jù)。包含運(yùn)行時(shí)常量池,用于存放編譯器生成的各種字面量和符號引用,這部分內(nèi)容是在類加載后進(jìn)入方法區(qū)運(yùn)行時(shí)常量池中。
5)堆
堆是整個(gè)內(nèi)存數(shù)據(jù)區(qū)最負(fù)責(zé)的部分,負(fù)責(zé)對象的創(chuàng)建。同時(shí),垃圾回收的主要工作也在于此。堆又進(jìn)一步進(jìn)行細(xì)分,主要是為了滿足垃圾回收。
堆的組成
Eden(伊甸園):對象創(chuàng)建的入口。
Survivor Space:用于保存在eden space內(nèi)存池中經(jīng)過垃圾回收后沒有被回收的對象,也就是“幸存還活著”的對象。
幸存者0區(qū)(Survivor 0 space)和幸存者1區(qū)(Survivor1 space):當(dāng)伊甸園的空間用完時(shí),程序又需要?jiǎng)?chuàng)建對象;此時(shí)JVM的垃圾回收器將對伊甸園區(qū)進(jìn)行垃圾回收,將伊甸園區(qū)中的不再被其他對象所引用的對象 進(jìn)行銷毀工作。同時(shí)將伊甸園中的還有其他對象引用的對象移動到幸存者0區(qū)。幸存者0區(qū)就是用于存放伊甸園垃圾回收時(shí)所幸存下來的JAVA對象。
當(dāng)將伊甸園中的還有其他對象引用的對象移動到幸存者0區(qū)時(shí),如果幸存者0區(qū)也沒有空間來存放這些對象時(shí),JVM的垃圾回收器將對幸存者0區(qū)進(jìn)行垃圾 回收處理,將幸存者0區(qū)中不在有其他對象引用的JAVA對象進(jìn)行銷毀,將幸存者0區(qū)中還有其他對象引用的對象移動到幸存者1區(qū)。幸存者1區(qū)的作用就是用于 存放幸存者0區(qū)垃圾回收處理所幸存下來的JAVA對象。
Tenured :對象經(jīng)過survivor 1 space內(nèi)存池,每經(jīng)歷過一次垃圾回收,年齡就增加1,超過設(shè)定閥值后,被移入終身代,當(dāng)然也包括由于擔(dān)保機(jī)制移入的對象。對于新生代和老年代,垃圾回收器對其態(tài)度不同。發(fā)生在新生代的回收頻率頻繁,大部分對象是“朝生夕死”,收集算法一般采用高效簡單的復(fù)制算法,也就是上文描述的對象轉(zhuǎn)移操作(Eden->survivor 0,survivor 0->survivor 1)。發(fā)生在該區(qū)域的垃圾回收為Young GC.對于老年代,由于大部分對象主要為存活率高的對象,垃圾回收器采用”標(biāo)記-整理“算法。發(fā)生在該區(qū)域的垃圾回收為FULL GC.
堆相關(guān)參數(shù)
(影響堆空間劃分,進(jìn)而會影響GC發(fā)生頻率)JVM調(diào)優(yōu)工作,主要是基于這些參數(shù),進(jìn)行適當(dāng)調(diào)整管理,達(dá)到調(diào)整堆內(nèi)存大小及比例大小,以滿足實(shí)際業(yè)務(wù)需求。另外還包括方法區(qū)。
-Xms:設(shè)置 Java 應(yīng)用程序啟動時(shí)的初始堆大??;
-Xmx:設(shè)置 Java 應(yīng)用程序能獲得的最大堆大小;
-Xss:設(shè)置線程棧的大小;
-XX:MinHeapFreeRatio:設(shè)置堆空間最小空閑比例。當(dāng)堆空間的空閑內(nèi)存小于這個(gè)數(shù)值時(shí),JVM 便會擴(kuò)展堆空間;
-XX:MaxHeapFreeRatio:設(shè)置堆空間的最大空閑比例。當(dāng)堆空間的空閑內(nèi)存大于這個(gè)數(shù)值時(shí),便會壓縮堆空間,得到一個(gè)較小的堆;
-XX:NewSize:設(shè)置新生代的大?。?br />
-XX:NewRatio:設(shè)置老年代與新生代的比例,它等于老年代大小除以新生代大??;
-XX:SurvivorRatio:新生代中 eden 區(qū)與 survivor 區(qū)的比例;
-XX:MaxPermSize:設(shè)置最大的持久區(qū)大??;
-XX:TargetSurvivorRatio: 設(shè)置 survivor 區(qū)的可使用率。當(dāng) survivor 區(qū)的空間使用率達(dá)到這個(gè)數(shù)值時(shí),會將對象送入老年代。
對象的生命周期
創(chuàng)建階段
1、檢查指令的參數(shù),是否能在常量池中定位到一個(gè)類的符號引用,如果是引用,判斷代表的類是否加載,解析和初始化過
2、如果沒有加載,則必須進(jìn)行加載,解析和初始化
3、類加載檢查,這時(shí)候已經(jīng)知道所需內(nèi)存的大小。
4、分配內(nèi)存。從java堆中劃分一塊大小確定的內(nèi)存。支持2種方式,至于選擇哪種方式分配內(nèi)存,與java堆是否規(guī)整有關(guān)(也就是是否空間空間和使用空間相互交錯(cuò)情況)。1.指針碰撞(分界點(diǎn)的指示器移動);2.空閑列表方式。然而,java堆是否規(guī)整,則取決于垃圾收集器的工作方式。此外,在分配內(nèi)存時(shí)還要考慮多線程情況,保證原子性。分配內(nèi)存的原子性有2種方式進(jìn)行保證(CAS 和 本地線程分配緩沖-XX +/- UseTLAB)。
5)、分配內(nèi)存完成后,初始化內(nèi)存空間(初始化為0)
6、維護(hù)對象的對象頭信息。如元數(shù)據(jù)信息,哈希碼,GC分代年齡,鎖信息,類元指針。
7、調(diào)用init方法,按照程序員意愿進(jìn)行初始化。
<7.1> 從超類到子類對static成員進(jìn)行初始化;
<7.2> 超類成員變量按順序初始化,遞歸調(diào)用超類的構(gòu)造方法;
<7.3> 子類成員變量按順序初始化,子類構(gòu)造方法調(diào)用。
應(yīng)用階段
分為強(qiáng)引用、軟引用、虛引用、若引用
不可視階段;
當(dāng)一個(gè)對象處于不可視階段,說明我們在其他區(qū)域的代碼中已經(jīng)不可以在引用它,其強(qiáng)引用已經(jīng)消失,例如,本地變量超出了其可視的范圍。
不可到達(dá)階段;
處于JVM對象生命周期不可到達(dá)階段的對象,在虛擬機(jī)所管理的對象引用根集合中再也找不到直接或間接的強(qiáng)引用,這些對象通常是指所有線程棧中的臨時(shí)變量, 所有已裝載的類的靜態(tài)變量或者對本地代碼接口(JNI)的引用。這些對象都是要被垃圾回收器回收的預(yù)備對象,但此時(shí)該對象并不能被垃圾回收器直接回收。其 實(shí)所有垃圾回收算法所面臨的問題是相同的——找出由分配器分配的,但是用戶程序不可到達(dá)的內(nèi)存塊。
可收集階段、終結(jié)階段、釋放階段 ;
當(dāng)一個(gè)對象處于可收集階段、終結(jié)階段與釋放階段時(shí)
<1> 回收器發(fā)現(xiàn)該對象已經(jīng)不可達(dá)。
<2> finalize方法已經(jīng)被執(zhí)行。
<3> 對象空間已被重用。
相關(guān)閱讀:
JVM(Java虛擬機(jī))簡介(動力節(jié)點(diǎn)Java學(xué)院整理)
以上所述是小編給大家介紹的Java JVM原理與調(diào)優(yōu)_動力節(jié)點(diǎn)Java學(xué)院整理,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時(shí)回復(fù)大家的。在此也非常感謝大家對腳本之家網(wǎng)站的支持!
相關(guān)文章
SpringBoot項(xiàng)目打包成jar后獲取classpath下文件失敗的解決
這篇文章主要介紹了SpringBoot項(xiàng)目打包成jar后獲取classpath下文件失敗的解決方案,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-07-07Spring事務(wù)框架之TransactionStatus源碼解析
這篇文章主要為大家介紹了Spring事務(wù)框架之TransactionStatus源碼示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-08-08基于Java中對域和靜態(tài)方法的訪問不具有多態(tài)性(實(shí)例講解)
下面小編就為大家?guī)硪黄贘ava中對域和靜態(tài)方法的訪問不具有多態(tài)性(實(shí)例講解)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-10-10MyBatisPlus?大數(shù)據(jù)量查詢慢的問題解決
本文主要介紹了MyBatis?Plus?解決大數(shù)據(jù)量查詢慢問題,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-02-02springboot+vue?若依項(xiàng)目在windows2008R2企業(yè)版部署流程分析
這篇文章主要介紹了springboot+vue?若依項(xiàng)目在windows2008R2企業(yè)版部署流程,本次使用jar包啟動后端,故而準(zhǔn)備打包后的jar文件,需要的朋友可以參考下2022-12-12Spring MVC 更靈活的控制 json 返回問題(自定義過濾字段)
本篇文章主要介紹了Spring MVC 更靈活的控制 json 返回問題(自定義過濾字段),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。2017-02-02SpringCloud?Eureka服務(wù)治理之服務(wù)注冊服務(wù)發(fā)現(xiàn)
這篇文章主要介紹了SpringCloud?Eureka服務(wù)治理服務(wù)注冊和服務(wù)發(fā)現(xiàn)概念詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-08-08AJAX?SpringBoot?前后端數(shù)據(jù)交互的項(xiàng)目實(shí)現(xiàn)
本文主要介紹了AJAX?SpringBoot?前后端數(shù)據(jù)交互的項(xiàng)目實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03