JAVA 運行機制小結

1、關系

Java運行包括4個方面Java代碼(.java)、Java編譯文件(.class)Java虛擬機Java應用程序接口。Java代碼通過編譯器編譯成為類文件,然后被裝載到字節(jié)碼內存中,通過類加載放入虛擬機中,最后通過操作系統(tǒng)和適配器實現,而JVM則處于核心地位。

2、Java虛擬機

Java虛擬機是java基礎部分,Java語言具有跨平臺的特性,這也是由JVM來實現的。更準確地說,是Sun利用JVM在不同平臺上的實現幫我們把平臺相關性的問題給解決了。Java語言支持通過JNI(Java Native Interface)來實現本地方法的調用,但是需要注意到,如果你在Java程序用調用了本地方法,那么你的程序就很可能不再具有跨平臺性,即本地方法會破壞平臺無關性。JVM包括類加載子系統(tǒng)、運行數據區(qū)、執(zhí)行引擎和本地方法接口。

生命周期總結:當一個java程序啟動時,JVM就產生一個實例;程序結束,實例也就消失了。Java虛擬機通常開始與一個main方法,這個方法是public static void修飾,JVM要調用必須是public,并且不通過對象調用,所以是static,而且由于JVM已經是底層,不會有任何返回,返回類型就成了void。

2.1類加載子系統(tǒng)

負責加載編譯好的.class字節(jié)碼文件,并裝入內存,使JVM可以實例化或以其它方式使用加載后的類。JVM的類加載子系統(tǒng)支持在運行時的動態(tài)加載,動態(tài)加載的優(yōu)點有很多,例如可以節(jié)省內存空間、靈活地從網絡上加載類,動態(tài)加載的另一好處是可以通過命名空間的分隔來實現類的隔離,增強了整個系統(tǒng)的安全性。類加載可分為4類

啟動加載器

啟動加載器:BootStrap Class Loader負責加載JAVAHOME/lib下的jar包,比如rt.jar文件中所有的Java類,Java的核心類都是由該ClassLoader加載。由于引導類加載器涉及到虛擬機本地實現細節(jié),開發(fā)者無法直接獲取到啟動類加載器的引用,所以不允許直接通過引用進行操作。

擴展類加載器

擴展類加載器:Extension Class Loader負載加載JAVA_HOME/lib/ext下的jar包,可以由開發(fā)者直接引用。

系統(tǒng)類加載器

系統(tǒng)類加載器:(System Class Loader)負載加載ClassPath下jar包及目錄,通常我們自己寫的Java類也是由該Class Loader加載。在Sun JDK中,系統(tǒng)類加載器的名字叫App Class Loader。

自定義類加載器

自定義類加載器:(User Defined Class Loader)由用戶自定義類的加載規(guī)則,可以手動控制加載過程中的步驟。

加載:尋找并導入指定類型(類和接口)的二進制信息,將過類的全限定名和ClassLoader加載類,主要是將指定的.class文件加載至JVM。
當類被加載以后,在JVM內部就以類的全限定名+Class Loader實例ID來標明類。在內存中,Class Loader實例和類的實例都位于堆中,它們的類信息都位于方法區(qū)。加載中采用的是c,需要進行類加載時,先判斷該類是不是已經進行加載,如果沒有就在父類中進行加載,如果父類都找不到,就加載BootStrap class,如果這些都沒有加載到,才加載自己的,這是Java安全性的一個保證。
加載階段和連接階段可能交叉進行,但是兩個階段建仍保持者固定的先手順序

鏈接:將二進制的類型信息合并到JVM運行狀態(tài)中。
第一步:驗證,驗證數據是否符合java類型,包括文件格式、元數據、字節(jié)碼以及符號引用驗證。
第二步:準備
第三步:解析

2.2運行時數據區(qū)

即內存空間,通常我們配置-Xms、-Xmx信息都是設置的內存,Xms表示初始內存,Xmx表示最大內存,Xmn表示設置年輕代內存等等。內存空間主要由Java堆heap、方法區(qū)method area、本地方法棧、程序計數器、Java棧組成。其中Java堆、方法取每個線程公有,而本地方法棧、程序計數器、Java棧是線程私有。

程序計數器

一塊較小的內存空間,是當前線程所執(zhí)行的字節(jié)碼的行號指示器。Java虛擬機的多線程是通過線程輪流切換執(zhí)行,一個確定時刻,一個處理器確切說是一個內核,只會執(zhí)行一條線程的指令,為了線程切換能夠恢復正確位置,所以需要有一個獨立的程序計數器。

Java虛擬機棧

同樣為線程私有,就是java方法執(zhí)行的內存模型,每個方法執(zhí)行時都會同時創(chuàng)建一個棧幀,用戶存儲局部變量表、操作棧、動態(tài)鏈接、方法出口信息。每一個方法被調用直至完成過程,就是入棧到出棧的過程。

局部變量表存放了各種基本數據類型,對象引用類型(一個指向對象起始地址的引用指針,或者一個代表對象相關的位置),和returnAddress類型(指向一條字節(jié)碼指令的地址)。局部變量表所需的內存空間在編譯期間完成分配,并且空間已經固定,不會改變。

本地方法棧

本地方法棧與Java?;疽粯?,只不過Java虛擬機棧是處理java方法(字節(jié)碼)服務,而本地方法棧是為虛擬機使用Native方法服務。

后期學習:查看java字節(jié)碼,使用 javap -verbose class文件;java -verbose文件名稱 注此處沒得后綴 是查看加載了哪些jar包和文件;javac -verbose java文件 是看虛擬器加載類哪些東西

Java堆 Heap

Java堆是虛擬機內存中最大的一塊,Java對是被所有線程共享的一塊內存區(qū),用來存放對象實例。Java堆也是垃圾收集器管理的主要區(qū)域,由于現在垃圾收集器基本都是采用的分代收集算法,所以Java堆基本可以分為新生代、老年代持久代,新生代再分為Eden空間、From survivor空間和To survivor空間。

新生代:用于存放新生的對象,對象在分配時首先分配到Eden區(qū),當Eden區(qū)沒有足夠空間時,就會進行一次minor GC。通過-Xmn設置新生代大小,-XX:NewRatio=參數 設置新生代與老年代的內存空間比,-XX:SurvivorRation=參數 設置Eden區(qū)和Survivor比。

當Eden區(qū)進行minor GC后,如果對象經過一次回收并且還存活,能被Survivor去接收,就會移到Survivor(From)區(qū),包括原From去中的對象,并將其年齡設置為1,每熬過一次minor GC年齡就會加1,當達到一定年齡后,就會晉升到老年代中。每次進行GC操作(Eden和From區(qū)),From區(qū)對象引入to區(qū),并且和To區(qū)進行邏輯互換,保證一個Survivor區(qū)是空的,如果在放入To或者survivor區(qū)中內存不夠時,會被放入Old區(qū)。Survivor設計成為兩個區(qū),應該回收中篩選更符合Old區(qū)條件的對象,因為Old區(qū)進行回收代價比較高

老年代:存放生命周期長的對象,或者是大對象(包括Eden區(qū)或者Survivor區(qū)無法放下的對象),當Old區(qū)被占滿時就會進行完成的垃圾回收Full GC(Major GC)包括新生代。Full GC完成后,留下來的內存就會方法Permanent區(qū)(持久代)中。

方法區(qū)

方法區(qū)和Java堆一樣,是各個線程共有的公共區(qū)域,用來存放已被虛擬機加載的類信息、常量、靜態(tài)變量、即時編譯器編譯后的代碼等數據。也可以被稱作“永久代”,但兩者本質上并不一樣,只是把GC分代收集擴展到方法區(qū)了,相對Java堆而言,垃圾收集行為在訪法區(qū)比較少見,主要針對常量池的回收和對類型的卸載。

運行時常量池

運行時常量池是屬于方法區(qū)的一部分,是存放編譯期生成的各種字面量和符號引用,當類被加載后,這些信息就會放入到訪法區(qū)運行時常量池中。另外,運行區(qū)常量還具有動態(tài)特征,不要求常量一定要在編譯期產生,運行期間也可能將新的常量放入常量池中,如String的intern方法。

直接內存

不是JVM中一部分,是由于new I/O 可以使用native直接分配堆外內存,然后通過存儲在java堆里面的DirectByteBuffer對象作為這塊內存的引用進行操作。

2.3 對象訪問

對象訪問在java中無處不在,即使最簡單的訪問,也會涉及到Java堆、Java棧和方法區(qū)。

如:Object obj = new Object();Object obj 作為對象引用,會被放入到Java本地棧中,通過一個reference獲取,而引用方式有兩種.

句柄式

先通過reference找到Java堆中的對象句柄地址,這個地址包含了對象實例數據(Java堆)和類型數據(方法區(qū))的各自具體內存地址,通過這個地址去訪問具體信息,這種方式的好處是如果reference存儲的是穩(wěn)定的句柄地址,在對象被移動時,只改變句柄中的地址指針,不用改變引用的地址。

直接式

就是reference引用時直接存儲的對象地址,具體實現時reference指針找到對象實例(Java堆),而對象實例中又存儲對象類型數據的地址,通過這個地址訪問對象類型數據(方法區(qū))。直接式的好處是節(jié)省了一對象定位的開銷,使得訪問速度更快。這兩種具體取舍是看虛擬機如果實現的。

基本數據類型訪問

基本數據類型由于字節(jié)類型大小都是固定的,所以需要的內存大小也都是固定的?;绢愋妥笥胰肿兞繒r,基本數據類型聲明是放在堆中的;而作為局部變量或者參數變量聲明時,是存放在棧中的,方法結束后就釋放。
對于String類型,字符串常量是放入字符串常量池,所以在方法區(qū)中,但是對于通過new String()出來的字符串,則在堆中。

3、性能優(yōu)化

多線程性能

有序性、原子性、可見性

原子性:保證內存原子性操作read、load、assign、use、store、write這六個,volatile關鍵字不具有原子性,

可見性:一個線程修改共享變量值時,另外一個線程立即知道這個修改。由于java內存模式是通過變量修改后立即同步到內存,然后變量讀取前從內存刷新變量值獲取依賴關系。

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • 從三月份找實習到現在,面了一些公司,掛了不少,但最終還是拿到小米、百度、阿里、京東、新浪、CVTE、樂視家的研發(fā)崗...
    時芥藍閱讀 42,793評論 11 349
  • JVM內存模型Java虛擬機(Java Virtual Machine=JVM)的內存空間分為五個部分,分別是: ...
    光劍書架上的書閱讀 2,774評論 2 26
  • JVM體系結構 JVM是一種解釋執(zhí)行class文件的規(guī)范技術。 我翻譯的中文圖: 類裝載器子系統(tǒng) 在JVM中負責裝...
    zhazhaxin閱讀 11,963評論 7 69
  • 前陣子, 突然收到一個短信,是三年前的一個屌絲朋友發(fā)來的, 讓我收到這個短信去找他。我知道他現在已經是飛黃騰達了,...
    Tim_leo閱讀 285評論 0 0
  • 方法和技巧的知識點 一、以教為學 二、刻意練習 刻意練習的核心假設是通過刻苦訓練達到的心理表征,從而增加成功的概率...
    beau遠方閱讀 346評論 0 0

友情鏈接更多精彩內容