1. 程式人生 > >JVM三部曲之執行時資料區 (第一部)

JVM三部曲之執行時資料區 (第一部)

在接下來的幾天想總結下,JVM相關的一些內容,比如下面的這三個內容算是比較核心知識點了

1.執行時資料區域: 在執行時資料區裡儲存類Class檔案元資料(方法區),物件和陣列(堆),方法引數區域性變數(棧)等。

2.垃圾回收機制: java 語言的優勢之一就是它的自動記憶體管理,主要回收執行時資料區域的堆記憶體裡的資料

3.類載入機制: 虛擬機器首先需要把編譯完成的位元組碼檔案通過類載入器來載入到執行時資料區域

一個段Java程式碼的生命週期都會少不了上圖這幾個步驟,也就是Java程式碼首先會被編譯成位元組碼檔案,之後被類載入器載入到執行時資料區域,以及執行,垃圾收集器回收物件等等。

但今天我想介紹第一個知識點《執行時資料區域》

1 執行時資料區

Java虛擬機器定義了一系列邏輯資料區域,有些是隨著虛擬機器的啟動而建立,虛擬機器的關閉而銷燬。還有一部分是隨著執行緒生命週期建立銷燬的。

我們有必要深入瞭解這塊的內容,因為它將決定伺服器效能,首先我們需要對整個執行時區域由整體的認識並且瞭解了每個區域的生命週期以及作用之後才能通過相應的調參來提升系統性能。除此之外還有助於快速定位虛擬機器的相關Error.

邏輯上可以劃出一下6個區域分別是

1.1 PC暫存器

全名叫做 Program Counter Register 既然是叫做暫存器了那麼肯定是需要存東西,那到底存的是什呢?
由於JVM同時可以處理多個執行緒所以就涉及到一些執行緒排程,當cpu暫停執行執行緒A把時間片讓給執行緒B的時候我們需要儲存執行緒A被暫停執行前的一些現場狀態,需要記錄當前執行到那一行位元組碼了,所以具備儲存現場的功能。

每條執行緒都有自己的pc暫存器,在任意時刻虛擬機器只會執行一個方法

如果執行的是方法不是native方法 pc暫存器則儲存指向當前執行位元組碼的指令地址

如果執行的是native方法 pc暫存器會儲存undefined

1.2 java虛擬機器棧

虛擬機器棧也是每條執行緒私有的區域,裡頭儲存棧幀(Frame),後面會重點介紹棧幀算是重點內容。方法的呼叫與返回基於棧幀來實現的。

1.3 虛擬機器堆

在Java虛擬機器中堆是所有執行緒都可以共享的記憶體區域,是存放所有類例項和陣列物件的地方。在虛擬機器啟動就根據相關堆引數,建立堆,他也是垃圾收集器工作的主要區域。
堆記憶體裡的物件不會被顯式的回收,而是由垃圾回收器回收

為了配合垃圾收集器的特性我們可以把堆分為年輕代和老年代

年輕代又分了Eden和survivor區,主要是為了配合垃圾回收演算法而這麼搞得。

1.4 方法區和執行時常量池

在Java虛擬機器中 方法區是可提供各個執行緒共享的執行時記憶體區域,它儲存了每一個類的結構資訊,例如執行時常量池,欄位和方法資料,建構函式和普通函式的位元組碼內容,一句話總結就是儲存元資料地方

執行時常量池是class檔案中每個類或介面常量池表的表示形式。它包括了若干不同的常量,比如 從編譯期可知的數值字面量到執行時才能解析獲得的方法或欄位引用等等。

建立時機
每個執行時常量池都在Java虛擬機器的方法區中分配,在載入類和介面到虛擬機器之後建立對應的執行時常量池

1.5 本地方法棧

如果我們想再Java底層裡呼叫別的語言程式碼的話就需要用到別的方法棧了,比如Java虛擬機器的實現會用到傳統的棧(C stack)來呼叫native方法,這個就是本地方法棧的應用,當然這個不是必須實現的,完全取決於虛擬機器的實現。

2 棧幀:

首先看下棧幀在虛擬機器記憶體中在什麼位置,

棧幀是用來儲存資料和部分過程結果的資料結構,同時也用來處理動態連結,方法返回,異常分派等工作。棧幀的生命週期是跟方法一致的,隨著方法的呼叫而建立,方法的結束或者異常而銷燬。
每個棧幀都由區域性變量表,運算元棧,動態連結組成的

2.1 區域性變量表 (Local variable)

每個棧幀內部都包含一組稱為區域性變量表的列表,變量表的長度在編譯期決定。
一個區域性變數可以儲存一個基本資料型別或一個物件引用(referance),returnAddress的資料。儲存long或double需要兩個區域性變數才能儲存。

當虛擬機器要使用區域性變量表裡的資料時通過索引來定位,預設從0開始,由於long和double佔用兩個區域性變數所以它的索引較特殊,取決於最小的那個值,比如某個long型別資料在索引n和n+1裡儲存了,那麼它對應的索引值就是n.
虛擬機器通過區域性變量表來完成方法呼叫時的引數傳遞。如果是類方法,它的引數依次從0開始的位置傳遞到區域性變量表,如果是例項方法則第0位置儲存所在物件的引用(this),從1開始傳遞引數。

2.2 運算元棧 (Operating Stack)

運算元棧是屬於棧幀中的棧,其實它的全名叫做當前棧幀的初運算元棧。棧,棧幀,運算元棧的關係需要梳理清楚:

  • 棧:是虛擬機器執行時資料區的一個邏輯區域,裡面儲存了一個個棧幀。
  • 棧幀:棧幀代表一個方法的整個生命週期,裡頭儲存了局部變量表,運算元棧,動態連結
  • 運算元棧: 剛剛建立時運算元棧是空的。虛擬機器提供一些指令從區域性變量表把一些常量或者變數值載入到運算元棧,也提供了從運算元棧取走資料的指令。
    呼叫方法時運算元棧用來準備呼叫方法引數以及接受方法的返回結果。

2.3 動態連結 (Dynamic Linking)。

動態連結是用來完成執行時繫結操作的。在棧幀中有一個指向常量池的當前類的一個引用。在class檔案裡一個方法要是呼叫其他方法或者方法其他成員變數,則需要通過符號引用來表示。

  • 動態連結的作用就是將符號引用轉換為直接引用。
  • 類載入的過程中將要解析尚未被解析的符號引用,並且把對變數的訪問轉換為正確的偏移量。