JVM原理之運行時數據區

JVM虛擬機

1. JVM在運行時主要包含java堆,方法區,程序計數器,JVM棧,本地方法棧。其中JAVA堆和方法區歸所有線程共有,而JVM棧和程序計數器歸線程私有。

程序計數器

  1. 程序計數器主要是執行線程中的指令,在多核環境中,線程需要進行切換。線程獲得CPU的執行後要恢復到原來的執行位置,這就是需要程序計數器保存當前線程執行位置。每個線程都有自己獨立的計數器。
  2. 如果線程正在執行一個JAVA方法,則程序計數器記錄的是當前字節碼指令。

虛擬機棧

  1. JAVA虛擬機棧是線程私有的,生命週期與線程相同。虛擬機棧描述的是java方法的內存模型。每個方法在執行時,線程都會創建一個棧幀,用於存儲局部變量表,操作數棧,動態鏈接,方法出口等信息。
    1.1 局部變量表存儲了基本類型和引用類型和returnAddress類型。局部變量表的空間在編譯期間已經確定,在方法運行期間不會改變。
  2. 每一個JAVA方法的執行實際上就是棧幀在的入棧和出棧操作。

本地方法棧

  1. 本地方法棧是JVM虛擬機用來調用本地方法,不同的虛擬機實現本地方法棧不同。

JAVA堆

  1. JAVA堆是JVM內存管理中最大的一塊內存區域,是所有線程共享的區域。堆在JVM啓動時創建,主要存放對象實例和數組。JAVA堆可以處於物理上不連續的空間,只要邏輯上連續即可。
  2. 現在的垃圾收集主要採用分代收集,通常將JAVA堆分爲新生代和老年代。其中,新生代又分爲Eden區,from surivior區,to surivior區。通常Eden區和surivior區比例爲8:2。
  3. 堆的大小都是可以控制的,通過-Xms和-Xmx進行控制。

方法區

  1. 方法區同java堆一樣,都是所有線程共享的區域,主要存儲被加載類的信息,常亮,靜態變量,及時編譯器變異後的代碼。
  2. 對於HotSpot而言,GC分代收集時,會回收方法區,也稱方法區爲”永久代”。這樣垃圾收集器就可以像管理java堆一樣管理方法區的內存。
  3. 垃圾收集行爲在方法區是很少出現的,即使出現了,回收內存成果也是不怎麼好。在方法區進行垃圾回收主要是回收常亮池和類型的卸載。

運行時常量池

  1. 運行時常量池是方法區的一部分。Class文件中除了有類的版本,字段,方法,接口等信息,還有一項信息就是常量池。
  2. 常量池另外一個重要特徵就是動態性,運行期間也可以將新的常量放入池中。常量池中主要存放符號引用和各種字面量。

直接內存

  1. JDK中NIO,採用了通道和緩衝一種新的I/O方式,NIO可以採用Native函數直接分配堆內存以外的內存。即不佔用JVM內存。
  2. 在JVM中同時存儲了一個DirectByteBuffer對象,它可以直接操縱直接內存。DirectByteBuffer對象的引用指向直接內存。
  3. 直接內存的存在避免了JVM和本地堆中來回複製數據。

對象創建

  1. 在應用程序中當生成一條New指令時,JVM就會從常量池中尋找代表該類型的符號引用,如果能找到該類的類型符號,則說明已經加載該類。如果沒有找到,則需要重新加載該符號代表的類。
  2. 找到代表該類的符號引用,JVM會分配一塊與該對象大小相等內存空間。分配內存空間時,可以採用指針碰撞法或空閒列表方式。
    這裏寫圖片描述

對象訪問定位

  1. 在JVM堆中生成對象之後,訪問對象的方式主要通過reference來訪問。在JVM中reference類型在JVM規範中只規定了一個指向對象的引用,但是沒有規定通過何種方式去定位,查找到對象。
  2. 目前主流的reference訪問對象方式主要有通過句柄和直接指針兩種方式。在流行的HotSpot中,採用直接指針方式進行定位對象。
    2.1 直接指針訪問是指 reference中存放了對象實例的指針(即對象地址)和對象類型數據指針的地址,通過reference可以直接在堆中定位到對象實例。對象類型的指針也是存放在堆中,但是該類型數據存放在方法區中。說起來有點拗口,通過圖可以直觀表示一下:
    這裏寫圖片描述
    2.2 句柄方式訪問是指在JVM堆中單獨分配一塊內存,用來存放句柄池。句柄池中存放的是都是句柄,而句柄中包含了對象實例數據與對象類型數據的地址信息。reference中存放的是句柄的地址。
    這裏寫圖片描述
    2.2.1 上圖可以看出,使用句柄訪問對象時,reference中存放的是句柄的地址,句柄是存放在JVM堆中的句柄池中,句柄中存放了對象數據實例指針和對象類型數據指針。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章