1. 程式人生 > >JVM基礎知識

JVM基礎知識

一.JVM執行時資料區包括哪幾部分?

  根據《深入理解Java虛擬機器》可知,執行時資料區通常包括這幾個部分:程式計數器(Program Counter Register)、Java棧(VM Stack)、本地方法棧(Native Method Stack)、方法區(Method Area)、堆(Heap)。
  程式計數器、Java棧和本地方法棧統稱為棧區,這部分是每個執行緒私有的。堆和方法區是所有執行緒共享的。
  
這裡寫圖片描述

二.每部分到底儲存了哪些內容?

1.程式計數器
  程式計數器(Program Counter Register),即PC暫存器。它儲存的是程式當前執行的指令的地址(也可以說儲存下一條指令的所在儲存單元的地址),可看作當前執行緒所執行的位元組碼的行號指示器。位元組直譯器通過改變該值來選取下一條需要執行的指令。

  由於在JVM中,多執行緒是通過執行緒輪流切換來獲得CPU執行時間的,因此,在任一具體時刻,一個CPU的核心只會執行一條執行緒中的指令,因此,為了能夠使得每個執行緒都線上程切換後能夠恢復在切換之前的程式執行位置,每個執行緒都需要有自己獨立的程式計數器,並且不能互相被幹擾,否則就會影響到程式的正常執行次序。因此,程式計數器是每個執行緒所私有的。

2.Java棧
  即虛擬機器棧(Java Vitual Machine Stack),也就是我們常常所說的棧,跟C語言的資料段中的棧類似。ava棧是Java方法執行的記憶體模型。

  當執行緒執行一個方法時,就會建立一個對應的棧幀,並將建立的棧幀壓棧。當方法執行完畢之後,便會將棧幀出棧。因此,執行緒當前執行的方法所對應的棧幀一定位於Java棧的頂部。由於每個執行緒當前正在執行的方法可能不同,因此每個執行緒都會有一個自己的Java棧,即Java棧也是執行緒私有的。
  每個棧幀用於儲存當前方法中的變量表、引數棧和方法出口等,區域性變數都儲存在這裡。
  區域性變量表存放了編譯期可知的基本資料型別、引用物件型別和返回值型別,因此區域性變量表所需的記憶體空間在編譯期就完成分配,執行期間不會改變其大小。

3.本地方法棧
  本地方法棧與Java棧的作用和原理非常相似。區別只不過是Java棧是為執行Java方法服務的,而本地方法棧則是為執行native方法(非Java語言實現)服務的。在HotSopt虛擬機器中直接就把本地方法棧和Java棧合二為一。

4.堆
  Java中的堆是用來儲存物件本身的以及陣列(當然,陣列引用是存放在Java棧中的),是垃圾收集器管理的主要區域,經常被稱為GC堆。堆中包含新生代和老年代,基本都採用分代收集演算法實現垃圾回收。
  堆是被所有執行緒共享的,在JVM中只有一個堆。

5.方法區
  在方法區中,儲存了每個類的資訊(包括類的名稱、方法資訊、欄位資訊)、靜態變數、常量等。方法區在JVM中也是一個非常重要的區域,它與堆一樣,是被執行緒共享的區域。

  在Class檔案中除了類的欄位、方法、介面等描述資訊外,還有一項資訊是常量池,用來儲存編譯期間生成的字面量和符號引用。
  在方法區中有一個非常重要的部分就是執行時常量池,它是每一個類或介面的常量池的執行時表示形式,在類和介面被載入到JVM後,對應的執行時常量池就被創建出來。當然並非Class檔案常量池中的內容才能進入執行時常量池,在執行期間也可將新的常量放入執行時常量池中,比如String的intern方法。
  HotSpot在永久代中實現方法區,但是其他JVM可能不是這樣,因此方法區不一定是在永久代。

三.HotSpot物件表示機制—–OOP-Klass二分模型

  在JVM中,所有物件都繼承自oopDesc類:
  

class oopDesc{
    private:
        volatile markOop _mark; //物件的執行時資訊,如hashcode、GC年齡、鎖等
        union _metaData{        //物件的元資料指標,指向描述物件的klass物件
            wideKlassOop _klass;
            narrowOop _compressed_klass;
        }_metaData;
    ......
}

  oopDesc父類中的_mark、 _metadata變數整體是物件的頭部。
  每當呼叫new建立一個新物件時,都會在堆中分配記憶體,並建立一個物件例項,其中包含物件頭和例項資料,然後將建立的結果的引用返回給Java棧中的區域性變量了。通過物件頭可以訪問物件的執行時資訊(_mark )和物件型別相關資訊( _metaData指標 )了。

  HotSpot中物件訪問採用直接指標的方式實現,如下圖所示:
  
這裡寫圖片描述

  Java程式是通過Java棧中的reference引用來操作堆上的具體物件的:
  1)當要訪問例項資料即類中的一般屬性時,可通過reference直接訪問堆中物件的例項資料
  2)當要訪問物件的方法和靜態屬性時,則通過_metaData指標訪問方法區的klass物件即可
  3)由於klass物件中含有虛擬函式表vtbl,因此每個物件通過_metaData指標訪問klass物件便可以找到所有的虛擬函式
  4)klass含有_super、_subclass等資訊,因此可以找到每個類的所有父類、子類、兄弟類等