【jvm】jvm介紹

JVM的基本特性:

  • 基於棧(Stack-based)的虛擬機: 不同於Intel x86和ARM等比較流行的計算機處理器都是基於寄存器(register)架構,JVM是基於棧執行的
  • 符號引用(Symbolic reference): 除基本類型外的所有Java類型(類和接口)都是通過符號引用取得關聯的,而非顯式的基於內存地址的引用。
  • 垃圾回收機制: 類的實例通過用戶代碼進行顯式創建,但卻通過垃圾回收機制自動銷燬。
  • 通過明確清晰基本類型確保平臺無關性: 像C/C++等傳統編程語言對於int類型數據在同平臺上會有不同的字節長度。JVM卻通過明確的定義基本類型的字節長度來維持代碼的平臺兼容性,從而做到平臺無關。
  • 網絡字節序(Network byte order): Java class文件的二進制表示使用的是基於網絡的字節序(network byte order)。爲了在使用小端(little endian)的Intel x86平臺和在使用了大端(big endian)的RISC系列平臺之間保持平臺無關,必須要定義一個固定的字節序。JVM選擇了網絡傳輸協議中使用的網絡字節序,即基於大端(big endian)的字節序。
Java類加載器的特點:
  • 層次結構:Java的類加載器按是父子關係的層次結構組織的。Boostrap類加載器處於層次結構的頂層,是所有類加載器的父類。
  • 代理模型(雙親委派):基於類加載器的層次組織結構,類加載器之間是可以進行代理的。當一個類需要被加載,會先去請求父加載器判斷該類是否已經被加載。如果父類加器已加載了該類,那它就可以直接使用而無需再次加載。如果尚未加載,才需要當前類加載器來加載此類。
    • 作用 :防止重複加載同一個.class 通過委託去向上面問一問,加載過了,就不用再加載一遍,保證核心.class不能被篡改。通過委託方式,不會去篡改核心.clas,即使篡改也不會去加載,即使加載也不會是同一個.class對象了。不同的加載器加載同一個.class也不是同一個Class對象。這樣保證了Class執行安全
    • 在這裏插入圖片描述
  • 可見性限制:子類加載器可以從父類加載器中獲取類,反之則不行。
  • 不能卸載: 類加載器可以載入類卻不能卸載它。但是可以通過刪除類加載器的方式卸載類。

java加載器:

  • Bootstrap加載器:Bootstrap加載器在運行JVM時創建,用於加載Java APIs,包括Object類。不像其他的類加載器由Java代碼實現,Bootstrap加載器是由native代碼實現的。
  • 擴展加載器(Extension class loader):擴展加載器用於加載除基本Java APIs以外擴展類。也用於加載各種安全擴展功能。
  • 系統加載器(System class loader):如果說Bootstrap和Extension加載器用於加載JVM運行時組件,那麼系統加載器加載的則是應用程序相關的類。它會加載用戶指定的CLASSPATH裏的類。
  • 用戶自定義加載器:這個是由用戶的程序代碼創建的類加載器。

類加載步驟:

  • 加載(Loading): 從文件中獲取類並載入到JVM內存空間。
  • 驗證(Verifying): 驗證載入的類是否符合Java語言規範和JVM規範。在類加載流程的測試過程中,這一步是最爲複雜且耗時最長的部分。大部分JVM TCK的測試用例都用於檢測對於給定的錯誤的類文件是否能得到相應的驗證錯誤信息。
  • 準備(Preparing): 根據內存需求準備相應的數據結構,並分別描述出類中定義的字段、方法以及實現的接口信息。
  • 解析(Resolving): 把類常量池中所有的符號引用轉爲直接引用。
  • 初始化(Initializing): 爲類的變量初始化合適的值。執行靜態初始化域,併爲靜態字段初始化相應的值。

java 運行時數據結構

  • PC 寄存器:每個線程都會有一個PC(Program Counter)寄存器,並跟隨線程的啓動而創建。PC寄存器中存有將執行的JVM指令的地址。

  • JVM 棧:每個線程都有一個JVM棧,並跟隨線程的啓動而創建。其中存儲的數據無素稱爲棧幀(Stack Frame)。JVM會每把棧楨壓入JVM棧或從中彈出一個棧幀。如果有任何異常拋出,像printStackTrace()方法輸出的棧跟蹤信息的每一行表示一個棧幀。

    棧幀:在JVM中一旦有方法執行,JVM就會爲之創建一個棧幀,並把其添加到當前線程的JVM棧中。當方法運行結束時,棧幀也會相應的從JVM棧中移除。棧幀中存放着對本地變量數組、操作數棧以及屬於當前運行方法的運行時常量池的引用。本地變量數組和操作數棧的大小在編譯時就已確定,所以屬在運行時屬於方法的棧幀大小是固定的。

  • 本地變量數組:本地變量數組的索引從0開始計數,其位置存儲着對方法所屬類實例的引用。從索引位置1開始的保存的是傳遞給該方法的參數。其後存儲的就是真正的方法的本地變量了。

  • 操作數棧:是方法的實際運行空間。每個方法變換操作數棧和本地變量數組,並把調用其它方法的結果從棧中彈或壓入。在編譯時,編譯器就能計算出操作數棧所需的內存窨,因此操作數棧的大小在編譯時也是確定的。

  • 本地方法棧:爲非Java編寫的本地代程定義的棧空間。也就是說它基本上是用於通過JNI(Java Native Interface)方式調用和執行的C/C++代碼。根據具體情況,C棧或C++棧將會被創建。

  • 方法區:方法區是被所有線程共用的內存空間,在JVM啓動時創建。它存儲了運行時常量池、字段和方法信息、靜態變量以及被JVM載入的所有類和接口的方法的字節碼。不同的JVM提供者在實現方法區時會通常有不同的形式。在Oracle的Hotspot JVM裏方法區被稱爲Permanent Area(永久區)或Permanent Generation(PermGen, 永久代)。JVM規範並對方法區的垃圾回收未做強制限定,因此對於JVM實現者來說,方法區的垃圾回收是可選操作。

  • 運行時常量池:一個存儲了類文件格式中的常量池表的內存空間。這部分空間雖然存在於方法區內,但卻在JVM操作中扮演着舉足輕重的角色,因此JVM規範單獨把這一部分拿出來描述。除了每個類或接口中定義的常量,它還包含了所有對方法和字段的引用。因此當需要一個方法或字段時,JVM通過運行時常量池中的信息從內存空間中來查找其相應的實際地址。

  • 數據堆:堆中存儲着所有的類實例或對象,並且也是垃圾回收的目標場所。當涉及到JVM性能優化時,通常也會提及到數據堆空間的大小設置。JVM提供者可以決定劃分堆空間或者不執行垃圾回收。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章