JVM深刻理解<一>

如下文章來自與:

http://www.jianshu.com/p/fabad9250b1b

1、什麼是JVM?

JVM是Java Virtual Machine(Java虛擬機)的縮寫,是經過在實際的計算機上仿真模擬各類計算機功能來實現的。由一套字節碼指令集、一組寄存器、一個棧、一個垃圾回收堆和一個存儲方法域等組成。JVM屏蔽了與操做系統平臺相關的信息,使得Java程序只須要生成在Java虛擬機上運行的目標代碼(字節碼),就可在多種平臺上不加修改的運行,這也是Java可以「一次編譯,處處運行的」緣由。java

 

2、JRE、JDK和JVM的關係

JRE(Java Runtime Environment, Java運行環境)是Java平臺,全部的程序都要在JRE下才可以運行。包括JVM和Java核心類庫和支持文件。數組

JDK(Java Development Kit,Java開發工具包)是用來編譯、調試Java程序的開發工具包。包括Java工具(javac/java/jdb等)和Java基礎的類庫(java API )。緩存

JVM(Java Virtual Machine, Java虛擬機)是JRE的一部分。JVM主要工做是解釋本身的指令集(即字節碼)並映射到本地的CPU指令集和OS的系統調用。Java語言是跨平臺運行的,不一樣的操做系統會有不一樣的JVM映射規則,使之與操做系統無關,完成跨平臺性。安全

JDK多線程

JDK(Java Development Kit) 是 Java 語言的軟件開發工具包(SDK)。JDK 物理存在,是 programming tools、JRE 和 JVM 的一個集合。函數

 


JRE工具

JRE(Java Runtime Environment)Java 運行時環境,JRE 物理存在,主要由Java API 和 JVM 組成,提供了用於執行 java 應用程序最低要求的環境。性能

 


3、JVM原理

一、JVM的體系結構

 


二、JVM生命週期介紹

Java實例對應一個獨立運行的Java程序(進程級別開發工具

1.啓動。啓動一個Java程序,一個JVM實例就產生。擁有public static void main(String[] args)函數的class能夠做爲JVM實例運行的起點。優化

2.運行。main()做爲程序初始線程的起點,任何其餘線程都可由該線程啓動。JVM內部有兩種線程:守護線程和非守護線程,main()屬於非守護線程,守護線程一般由JVM使用,程序能夠指定建立的線程爲守護線程。

3.消亡。當程序中的全部非守護線程都終止時,JVM才退出;若安全管理器容許,程序也可使用Runtime類或者System.exit()來退出。

JVM執行引擎實例則對應了屬於用戶運行程序線程它是線程級別的。

三、Java類加載器

 Java加載類的過程

 


1.裝載(loading):負責找到二進制字節碼並加載至JVM中,JVM經過類名、類所在的包名、ClassLoader完成類的加載。所以,標識一個被加載了的類:類名 + 包名 + ClassLoader實例ID。

2.連接(linking):負責對二進制字節碼的格式進行校驗、初始化裝載類中的靜態變量以及解析類中調用的接口。

完成校驗後,JVM初始化類中的靜態變量,並將其賦值爲默認值。

最後對比類中的全部屬性、方法進行驗證,以確保要調用的屬性、方法存在,以及具有訪問權限(例如private、public等),不然會形成NoSuchMethodError、NoSuchFieldError等錯誤信息。

3.初始化(initializing):負責執行類中的靜態初始化代碼、構造器代碼以及靜態屬性的初始化,如下四種狀況初始化過程會被觸發。

四、JVM類加載順序

層級結構

 


1.Booststrap ClassLoader

跟ClassLoader,C++實現,JVM啓動時初始化此ClassLoader,並由此完成$JAVA_HONE中jre/lib/rt.jar(Sun JDK的實現)中全部class文件的加載,這個jar中包含了java規範定義的全部接口以及實現。

2.Extension ClassLoader

JVM用此classloader來加載擴展功能的一些jar包

3.System ClassLoader

JVM用此ClassLoader來加載啓動參數中指定的ClassPath中的jar包以及目錄,在Sun JDK中ClassLoader對應的類名爲AppClassLoader。

4.User-Defined ClassLoader

User-Defined ClassLoader是Java開發人員繼承ClassLoader抽象類實現的ClassLoader,基於自定義的ClassLoader可用於加載非ClassPath中的jar以及目錄。

五、委派模式(Delegation Mode)

 


當JVM加載一個類的時候,下層的加載器會將任務給上一層類加載器,上一層加載檢查它的命名空間中是否已經加載這個類,若是已經加載,直接使用這個類。若是沒有加載,繼續往上委託直到頂部。檢查以後,按照相反的順序進行加載。若是Bootstrap加載器不到這個類,則往下委託,直到找到這個類。一個類能夠被不一樣的類加載器加載。

可見性限制:下層的加載器可以看到上層加載器中的類,反之則不行,委派只能從下到上

不容許卸載類:類加載器能夠加載一個類,但不可以卸載一個類。可是類加載器能夠被建立或者刪除。

六、JVM執行引擎

類加載器將字節碼載入內存後,執行引擎以java字節碼爲單元,讀取java字節碼。java字節碼機器讀不懂,必須將字節碼轉化爲平臺相關的機器碼。這個過程就是由執行引擎完成的。

 


在執行方法時JVM提供了四種指令來執行

invokestatic:調用類的static方法。

invokevirtual:調用對象實例的方法。

invokeinterface:將屬性定義爲接口來進行調用。

invokespecial:JVM對於初始化對象(Java構造器的方法爲:)以及調用對象實例的私有方法時。

主要的執行計數:

解釋,即時執行,自適應優化、芯片級直接執行。

解釋屬於第一代JVM

即時編譯JIT屬於第二代JVM

自適應優化(目前sun的HotspotJVM採用這種技術),吸收第一代JVM和第二代JVM的經驗,採用二者結合的方式,開始對全部的代碼都採用解釋執行的方式,並監視代碼執行狀況,而後對那些常常調用的方法啓動一個後臺線程,將其編譯爲本地代碼,並進行優化。若方法再也不頻繁使用,則取消編譯過代碼,仍對其進行解釋執行。

七、java運行時數據區

 


PC寄存器

用於存儲每一個線程下一步將要執行的JVM指令,若該方法爲native的,則PC寄存器中不存儲任何信息。Java多線程狀況下,每一個線程都有一個本身的PC,以便完成不一樣線程上下文環境的切換。

JVM棧

JVM棧是線程私有的,每一個線程建立的同時都會建立JVM棧,JVM棧中存放當前線程中局部基本類型的變量(Java中定義的八種基本類型:boolean、char、byte、short、int、long、float、double)、部分的返回結果以及Stack Frame,非基本類型的對象在JVM棧上僅存放一個指向堆的地址。

堆(Heap)

它是JVM用來存儲對象實例以及數組值的區域,能夠認爲Java中全部經過new建立的對象的內存都在此分配,Heap中的對象的內存須要等待GC進行回收。

堆在JVM啓動的時候就被建立,堆中儲存了各類對象,這些對象被自動管理內存系統(Automatic Storage Management System),也就是常說的「Garbage Collector(垃圾回收器)」管理。這些對象無需、也沒法顯示地被銷燬。

JVM將Heap分爲兩塊:新生代New Generation和舊生代Old Generation

 


堆是JVM中全部線程共享的,所以在其上進行對象內存的分配均須要進行加鎖,致使new對象的開銷比較大。

Sun Hotspot JVM爲了提高對象內存分配的效率,對於全部建立的線程都會分配一塊獨立的空間TLAB(Thread Local Allocation Buffer),其大小由JVM根據運行的狀況計算而得,在TLAB上分配對象時不須要加鎖,所以JVM在給線程對象分配內存時會盡可能的在TLAB上分配,在這種狀況下JVM中分配對象內存的性能和C基本是同樣的,但若是對象過大的話則仍然要直接使用堆空間分配。

TLAB僅做用於新生代的Eden Space,所以在編寫Java程序時,一般多個小的對象比大的對象分配起來更加高效。

全部新建立的Object都將會存儲在新生代Young Generation中。若是Young Generation的數據在一次或屢次GC後存活下來,那麼將被轉移到OldGeneration。新的Object老是建立在Eden Space。

方法區域(Method Area)

在Sun JDK中這塊區域對應的爲PermanetGeneration,又稱爲持久代。

方法區域存放所加載類的信息(名稱、修飾符等)、類中的靜態變量、類中定義爲final類型的常量、類中的Field信息、類中的方法信息,當開發人員在程序中經過Class對象中的getName,isInstance等方法來獲取信息時,這些數據都來源於方法區域,同時方法區域也是全局共享的,在必定條件下它也會被GC,當方法區域須要使用的內存超過其容許的大小時,就會拋出OutOfMemory的錯誤信息。

運行時常量池(Runtime Constant Pool)

存放的爲類中的固定常量信息、方法和Field的引用信息等,其空間從方法區域中分配。

本地方法堆棧(Native Method Stacks)

JVM採用本地方法堆來支持native方法的執行,此區域用於存儲每一個native方法調用的狀態。

八、JVM垃圾回收

GC的基本原理:將內存中再也不被使用的對象進行回收,GC中用於回收的方法稱爲收集器,因爲GC須要消耗一些資源和時間,Java在對對象生命週期特徵進行分析後,按照新生代、舊生代的方式來對對象進行收集,以儘量的縮短GC對應用形成的暫停。

對新生代的對象收集稱爲minor GC

對舊生代的對象收集稱爲Full GC

程序中主動調用System.gc()強制執行的GC爲Full GC。

不一樣的對象引用類型,GC會採用不一樣的方法進行回收,JVM對象的引用分爲了四種類型

強引用:默認狀況下,對象採用的均爲強引用(這個對象的實例沒有其餘對象引用時, GC時纔會被回收)

軟引用:軟引用是Java中提供的一種比較適合於緩存場景的應用(只有內存不夠的狀況下才會被GC)

弱引用:在GC時必定會被GC回收。

虛引用:虛引用只是用來得知對象是否被GC。

做者:空有一身才華和一張帥氣的臉 連接:http://www.jianshu.com/p/fabad9250b1b 來源:簡書 著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。
相關文章
相關標籤/搜索