1. 程式人生 > >JVM知識(上)

JVM知識(上)

其他 tac 方法區 方式 turn 創建 ring 堆棧幀 運行時

目錄

  • 什麽是JVM?
  • JVM的生命周期
  • JVM的體系結構
  • JVM的數據類型

java虛擬機被稱為“虛擬”,因為它是一個抽象的計算機定義的規範。要運行一個Java程序,需要一個抽象的規範的具體實現。以下內容主要還是參考《Inside JVM》

什麽是JVM?

JVM是Java Virtual Machine(Java虛擬機)的縮寫,JVM是一種用於計算設備的規範,它是一個虛構出來的計算機,是通過在實際的計算機上仿真模擬各種計算機功能來實現的。JVM三種不一樣的地方:抽象的規範,一個具體的實現,運行時的實例。

JVM的生命周期

java虛擬機種運行的一個實例有著明確的“使命”:運行一個java程序,當程序啟動時,產生一個運行實例,當程序運行完成時,實例就沒了。如果同時啟動三個java程序,在同一臺電腦上,使用相同的實現方法,你就會得到三個java虛擬機的實例,每個java程序運行在自己的虛擬機實例上面。

Java虛擬機實例通過調用一些初始類的main()方法來開始運行其單獨應用程序,該main()方法必須時公共(public),靜態(static),無返回值的(void),並且接受一個字符串數組的參數(String[] args),按照上面定義的main()方法,任何一個類的main方法都可以作為程序啟動的起點。


public class Application {
      public static void main(String[] args) {
         SpringApplication.run(Application.class, args);
      }
}

在java虛擬機中,線程分兩種:守護線程(daemon,也可以成為後臺線程)和 非守護線程(non-daemon,前臺線程)。


daemon守護線程是JVM自己用的,就比如我們常說的垃圾回收。non-daemon非守護線程,應用程序啟動了main(),然後再調用我們自己寫的方法。

一個java程序在運行時,只要非守護線程一直運行,那麽java虛擬機實例就一直存在,當所有的java非守護線程中斷時,java虛擬機實例也就消失了。當然我們也可以直接通過類Runtime或者類System調用exit()方法來使程序中斷。

JVM的體系結構

在java虛擬機規範中,java虛擬機的行為是由子系統,內存區域,數據類型和指令來描述的。這些組件的目的與其說是決定內部架構的實現,更提供了一種嚴格定義的外部行為的實現。規範定義了所需的任何Java虛擬機的行為來實現這些抽象組件及其之間的交互。

一個Java虛擬機,包括主要的子系統和內存區域中描述的規範如前一章中提到,每個Java虛擬機有一個類裝入器子系統:加載機制類型(類和接口)指定完全限定的名稱。每個Java虛擬機還提供一個執行引擎:一種機制負責執行的指令包含在加載的類的方法。

技術分享圖片

當一個Java虛擬機運行一個程序的時候,他需要內存存儲更多的東西,包括直接碼和其它信息摘錄加載類文件,程序實例化對象,參數方法,返回值,局部變量,計算的中間結果。雖然相同的數據區域運行在每一個java虛擬機的實現上,規範是抽象的,但具體運行這些數據區域的細節的時候還是需要(設計者)實現者來具體實現。
不同的java虛擬機的實現有很多不同的內存限制,有些實現需要很多的內存為其工作,而有的實現卻需要的很少;有的實現可以利用java虛擬內存,有的卻不可以;運行時數據區域的抽象性質規範更容易在各種各樣的電腦和設備實現Java虛擬機。
一些運行時的數據區被一個程序線程或者其它獨一無二的線程所共享,每一個java虛擬機實例都有一個方法區(method area)和堆(heap)。這些區域內運行的所有線程共享虛擬機。當JVM加載一個類文件(class文件)時,JVM會從二進制數據中解析出包含信息類型的類文件。它會把這些類的文件送到方法區裏面去。當程序運行時,虛擬機將所有對象實例化到堆(heap)。
技術分享圖片

因為每個新線程啟動,它有自己的電腦註冊(程序計數器)和Java堆棧。如果線程正在執行Java方法(不是一個本地方法),pc寄存器的值顯示為要執行下一個指令。Java堆中存儲著Java線程(非原生)方法調用的狀態。Java方法調用的狀態包括局部變量、被調用的參數,它的返回值(如果有的話),中間的計算。本地方法調用的狀態以具體實現相關的方式在本地方法棧存儲著,以及可能在寄存器或其他具體實現相關的內存區域。Java堆棧由堆棧幀(幀)組成。一個堆棧幀包含一個Java方法調用的狀態,說白了就是每個棧就是一個每個調用的方法。當一個線程調用一個方法時,Java虛擬機會分配一個新的棧給那個線程的方法。當方法完成時,虛擬機就會丟棄此方法的棧。Java虛擬機沒有寄存器來保存中間數據值。指令集被使用在Java堆棧存儲這些中間數據值。
技術分享圖片

上圖中,線程1和2是執行java方法,線程3 執行本地的方法。

JVM的數據類型

Java虛擬機通過操作某些類型的數據來進行計算。這些數據類型和操作都嚴格定義的Java虛擬機規範。可以分為一組基本類型和引用類型。變量的原始類型保存原始值,變量的引用類型值的引用。引用值引用對象,但不是對象本身。原始值,相比之下,不參考任何東西。他們是實際數據本身。

技術分享圖片

所有原始類型的Java編程語言,除了布爾類型,其它都是是Java虛擬機的基本類型。編譯器將Java源代碼轉換為字節碼時,它使用int或字節來表示布爾值。在Java虛擬機中,錯誤的是由整數0和真正的任何非零的整數,業務涉及到布爾值使用int。布爾訪問數組作為字節數組,盡管它們可能在堆上表示為字節數組或字段。原始類型的Java編程語言以外的布爾形成了數字類型的Java虛擬機。之間的數值類型為: byte, short, int, long, , char。與Java編程語言一樣,Java虛擬機的基本類型有相同的範圍。長在Java虛擬機總是像一個64位表示整數,獨立於底層主機平臺。Java程序員可以使用適用於Java虛擬機而不在原始類型中的returnValue類型。這種原始的類型在Java程序被使用。引用類型分為三種:類類型,接口類型和數組類型。所有三種類型值對動態創建對象的引用。class type值對類實例的引用。array type值是數組的引用,這是成熟的對象在Java虛擬機。interface type值是實現一個接口的類實例的引用。另一個值是null值的引用,這表明沒有引用任何對象的引用變量。Java虛擬機規範定義了每個數據類型的值的範圍,但沒有定義他們的大小。bits比特數用來存儲每個數據類型。

下篇將詳細介紹JVM中heap,stack,method area如何工作的

JVM知識(上)