1. 程式人生 > >深入理解Java虛擬機器 JVM基本框架

深入理解Java虛擬機器 JVM基本框架

JVM基本框架

首先是JVM的整圖結構圖:
這裡寫圖片描述

圍繞JVM記憶體空間有三個重要的組成部分(綠色框):

另外的內容還包括:

  • Javac編譯器(.java源程式如何如何編譯成類檔案?java的語法糖?)
  • 程式的併發執行

JVM記憶體空間

三個重要組成部分都是圍繞JVM執行時的記憶體模型展開,因此先簡單介紹這部分。

  • 虛擬機器棧:虛擬機器棧描述的是方法Method執行的記憶體模型:每個方法被呼叫時都會建立一個棧幀,存放方法區域性變量表、運算元棧和動態連結,方法出口地址。棧幀結構如下:
    這裡寫圖片描述

    • 每個執行緒都有私有的棧幀空間,相互獨立。
    • 當前執行方法擁有頂部當前棧幀,方法的呼叫和返回過程就是棧幀的入棧和出棧過程。
    • 區域性變量表:基本資料型別和物件引用區域性變數、方法引數和隱含的this指標。
    • 運算元棧:JVM位元組碼指令集是基於運算元棧的(就像x86硬體指令集基於通用暫存器一樣)。
    • 虛擬機器棧可通過VM引數-Xss(每個執行緒棧尺寸)設定棧空間大小,如果當前執行緒申請的棧深度大於虛擬機器允許的深度,StackOverFlowError異常。
  • 本地方法棧:與虛擬機器棧類似,只是服務物件是Native方法。

  • 程式計數器:當前執行緒程式碼執行指示器,每個執行緒獨立。
  • :幾乎所有物件例項在堆中分配空間(棧上只是堆中例項的引用),為所有執行緒共享。
    • 堆是垃圾收集器GC的主要管理區域(在講到GC時會有堆上空間的細分)
    • JIT編輯器的逃逸技術等,使某些物件也能夠在棧上分配空間。
  • 方法區:存放被載入的類資訊、常量(final型別常量,常量池)、靜態變數、即時編譯器編譯後的原生代碼。

    • HotSpot JVM用持久代(Permanet Generation)來存放方法區。
    • 方法去垃圾回收主要是常量池回收和型別解除安裝。

    [執行時常量池](Runtime Constant Pool)

    • 是方法區一部分,與Class檔案中[常量池](Constant Pool Table)相對應,當類載入後,Class檔案的[常量池]將存放在[執行時常量池]中。
    • [常量池]存放編譯期生成的字面量(字串”abc”,宣告為final常量等)和符號引用
      (類和介面全限定名、欄位名、方法名等)。

物件的記憶體佈局和建立

1)堆是物件儲存區域,那麼一個物件記憶體佈局是怎樣的?

這裡寫圖片描述


2)虛擬機器如何能夠解讀物件例項資料?即虛擬機器如何知道物件中各欄位具體偏移?

  • 將類資訊指標置於物件頭內,如上圖。klass pointer指向方法區內物件型別元資料。這也是HotSpot的做法。
    這裡寫圖片描述

  • 通過控制代碼。
    這裡寫圖片描述


    3)物件如何建立?

Point originOne = new Point(0,0);

在類被裝載、連線和初始化,這個類就隨時都可能使用了。物件例項化和初始化是就是物件生命的起始階段的活動,在這裡我們主要討論物件的初始化工作的相關特點。
Java 編譯器在編譯每個類時都會為該類至少生成一個例項初始化方法–即 “<init>()” 方法。此方法與原始碼中的每個構造方法相對應,如果類沒有明確地宣告任何構造方法,編譯器則為該類生成一個預設的無參構造方法,這個預設的構造器僅僅呼叫父類的無參構造器,與此同時也會生成一個與預設構造方法對應的 “<init>()” 方法.
通常來說,<init>() 方法內包括的程式碼內容大概為:呼叫另一個<init>() 方法;對例項變數初始化;與其對應的構造方法內的程式碼。
如果構造方法是明確地從呼叫同一個類中的另一個構造方法開始,那它對應的 <init>()方法體內包括的內容為:一個對本類的 <init>()方法的呼叫;對應用構造方法內的所有位元組碼。
如果構造方法不是通過呼叫自身類的其它構造方法開始,並且該物件不是 Object 物件,那<init>() 法內則包括的內容為:一個對父類 <init>()方法的呼叫;對例項變數初始化方法的位元組碼;最後是對應構造子的方法體位元組碼。
如果這個類是 Object,那麼它的 <init>() 方法則不包括對父類 <init>() 方法的呼叫。