《深刻理解Java虛擬機》(二)Java虛擬機運行時數據區

Java虛擬機運行時數據區 詳解

2.1 概述

本文參考的是周志明的 《深刻理解Java虛擬機》第二章 ,爲了整理思路,簡單記錄一下,方便後期查閱。html

2.2 運行時數據區域

Java虛擬機在Java程序運行時會將內存區域劃分紅若干個不一樣的區域,各自負責不一樣的職責,這些區域都有各自的用途。
  1. Java虛擬機運行時數據區分爲如下幾個部分。
  2. 方法區、虛擬機棧、本地方法棧、堆、程序計數器,以下圖所示:
圖片來源於網絡若有侵權請私信刪除

圖片描述

2.2.1 程序計數器

程序計數器是一塊較小的內存空間,能夠看做當前線程所執行的字節碼行號指示器。須要注意如下幾點內容:java

  1. 程序計數器是線程私有,各線程之間互不影響。
  2. 在任何一個肯定的時刻,一個處理器都只會執行一條線程中的指令。
  3. 若是正在執行java方法,計數器記錄的是正在執行的虛擬機字節碼指令地址。
  4. 若是是native方法,則計數器值爲空(native 方法 指得就是Java程序調用了非Java代碼,算是一種引入其它語言程序的接口)。
  5. 程序計數器也是在Java虛擬機規範中惟一沒有規定任何OutOfMemoryError異常狀況的區域。

2.2.2 java虛擬機棧

  • 可經過參數 棧幀是方法運行期的基礎數據結構棧容量可由-Xss設置
  1. Java虛擬機棧是線程私有的,它的生命週期與線程相同。
  2. 每個方法被調用直至執行完成的過程,就對應着一個棧幀在虛擬機棧中從入棧到出棧的過程。
  3. 虛擬機棧是執行Java方法的內存模型(也就是字節碼)服務:每一個方法在執行的同時都會建立一個棧幀,用於存儲 局部變量表操做數棧動態連接方法出口等信息。
  • 局部變量表:32位變量槽,存放了編譯期可知的各類基本數據類型、對象引用、returnAddress類型。
  • 操做數棧:基於棧的執行引擎,虛擬機把操做數棧做爲它的工做區,大多數指令都要從這裏彈出數據、執行運算,而後把結果壓回操做數棧。
  • 動態鏈接:每一個棧幀都包含一個指向運行時常量池(方法區的一部分)中該棧幀所屬方法的引用。持有這個引用是爲了支持方法調用過程當中的動態鏈接。Class文件的常量池中有大量的符號引用,字節碼中的方法調用指令就以常量池中指向方法的符號引用爲參數。這些符號引用一部分會在類加載階段或第一次使用的時候轉化爲直接引用,這種轉化稱爲靜態解析。另外一部分將在每一次的運行期間轉化爲直接應用,這部分稱爲動態鏈接
  • 方法出口:返回方法被調用的位置,恢復上層方法的局部變量和操做數棧,若是無返回值,則把它壓入調用者的操做數棧。
  1. 局部變量表所需的內存空間在編譯期間完成分配,當進入一個方法時,這個方法須要在幀中分配多大的局部變量空間是徹底肯定的。
  2. 在方法運行期間不會改變局部變量表的大小。主要存放了編譯期可知的各類基本數據類型、對象引用 (reference類型)、returnAddress類型)

java虛擬機棧,規定了兩種異常情況:

  1. 若是線程請求的深度大於虛擬機所容許的深度,將拋出StackOverflowError異常。
  2. 若是虛擬機棧動態擴展,而擴展時沒法申請到足夠的內存,就會拋出OutOfMemoryError異常。

2.2.3 本地方法棧

  • 可經過參數 棧容量可由-Xss設置
  1. 虛擬機棧爲虛擬機執行Java方法(也就是字節碼)服務。
  2. 本地方法棧則是爲虛擬機使用到的Native方法服務。有的虛擬機(譬如Sun HotSpot虛擬機)直接就把本地方法棧和虛擬機棧合二爲一。

2.2.4 java堆

  • 可經過參數 -Xms 初始堆大小-Xmx 最大堆大小-Xmn 新生代` 設置
  1. Java堆是被全部線程共享,是Java虛擬機所管理的內存中最大的一塊 Java堆在虛擬機啓動時建立。
  2. Java堆惟一的目的是存放對象實例,幾乎全部的對象實例和數組都在這裏。
  3. Java堆爲了便於更好的回收和分配內存,能夠細分爲,新生代和老年代segmentfault

    **再細緻一點的有Eden空間、From Survivor空間、To Survivor區**。
    • 新生代:包括Eden區、From Survivor區、To Survivor區,系統默認大小Eden:Survivor=8:1:1。
    • 老年代:在年輕代中經歷了N次垃圾回收後仍然存活的對象,就會被放到老年代中。所以,能夠認爲老年代中存放的都是一些生命週期較長的對象。
  4. Survivor空間等Java堆能夠處在物理上不連續的內存空間中,只要邏輯上是連續的便可(就像咱們的磁盤空間同樣。在實現時,既能夠實現成固定大小的,也能夠是可擴展的)。
  • 據Java虛擬機規範的規定,當方法區沒法知足內存分配需求時,將拋出OutOfMemoryError異常。

2.2.5 方法區

  • 可經過參數-XX:MaxPermSize設置
  1. 線程共享內存區域,用於儲存已被虛擬機加載的類信息、常量、靜態變量,即編譯器編譯後的代碼,方法區也稱持久代(Permanent Generation)。
  2. 雖然Java虛擬機規範把方法區描述爲堆的一個邏輯部分,可是它卻有一個別名叫作Non-Heap(非堆),目的應該是與Java堆區分開來。
  3. 如何實現方法區,屬於虛擬機的實現細節,不受虛擬機規範約束。
  4. 方法區主要存放java類定義信息,與垃圾回收關係不大,方法區能夠選擇不實現垃圾回收,但不是沒有垃圾回收。
  5. 方法區域的內存回收目標主要是針對常量池的回收和對類型的卸載。
  6. 運行時常量池,也是方法區的一部分,虛擬機加載Class後把常量池中的數據放入運行時常量池。

2.2.6 運行時常量池

  • 可經過參數-XX:PermSize-XX:MaxPermSize設置
  • 常量池(Constant Pool):常量池數據編譯期被肯定,是Class文件中的一部分。存儲了類、方法、接口等中的常量,固然也包括字符串常量。
  • 字符串池/字符串常量池(String Pool/String Constant Pool):是常量池中的一部分,存儲編譯期類中產生的字符串類型數據。
  • 運行時常量池(Runtime Constant Pool):方法區的一部分,全部線程共享。虛擬機加載Class後把常量池中的數據放入到運行時常量池。常量池:能夠理解爲Class文件之中的資源倉庫,它是Class文件結構中與其餘項目資源關聯最多的數據類型。
  1. 常量池中主要存放兩大類常量:字面量(Literal)和符號引用(Symbolic Reference)。
  2. 字面量:文本字符串、聲明爲final的常量值等;。
  3. 符號引用:類和接口的徹底限定名(Fully Qualified Name)、字段的名稱和描述符(Descriptor)、方法的名稱和描述符。
  • JDK1.6以前字符串常量池位於方法區之中
  • JDK1.7字符串常量池已經被挪到堆之中

2.2.7 直接內存

  • 可經過-XX:MaxDirectMemorySize指定,若是不指定,則默認與Java堆的最大值(-Xmx指定)同樣
  • 直接內存(Direct Memory)並非虛擬機運行時數據區的一部分,也不是Java虛擬機規範中定義的內存區域,可是這部份內存也被頻繁地使用,並且也可能致使OutOfMemoryError異常出現。

2.3 hotspot虛擬機對象探祕

2.3.1 對象的建立

  • 主要探討HotSpot虛擬機在Java堆中對象分配、佈局和訪問的全過程
  • 虛擬機遇到new指令時
  1. 首先去檢查這個指令的參數可否在常量池中定位到一個類的符號引用,而且檢查引用表明的類是否已被加載、解析和初始化過。若是沒有,則執行類加載過程(第7章 虛擬機類加載機制)。
  2. 加載檢查經過後,分配內存(內存在類加載完成後即可徹底肯定)。
  3. 內存分配完成後,虛擬機對對象進行必要的設置,如對象是哪一個類的實例、如何找到類的元數據信息等(都放在對象的對象頭中)。
  4. 從虛擬機角度看,一個新的對象產生了,但從java程序視角看,對象建立纔剛剛開始,由於<init>方法尚未執行,,全部字段爲零。執行new指令以後會接着執行<init>方法(構造方法),進行初始化,這樣一個真正可用的對象纔算完成產生。

2.3.2 對象的內存佈局

對象在內存中存儲的佈局能夠分爲3塊區域:對象頭、實例數據、對齊填充數組

對象頭包含兩部分(Header)網絡

  • 存儲對象自身的 運行時數據,如哈希碼、GC分代年齡等。長度在32位和64位的虛擬機中,分別爲32bit、 64bit,官方稱它爲「Mark Word」。
  • 類型指針,對象指向它的類元數據的指針,虛擬機經過這個指針來肯定這個對象是哪一個類的實例。

注:若是對象是一個java數組,對象頭中還必須有一塊記錄數據長度的數據數據結構

實例數據(InstanceData)jvm

  • 對象真正存儲的有用信息,也是程序中定義的各類類型的字段內容。

對齊填充(Padding)工具

  • 因爲HotSpot虛擬機要求對象的起始地址必須是8字節的整數倍,通俗的說,就是對象大小必須是8字節的整數倍。對象頭正好是8字節的倍數。當實例數據部分沒有對齊時,須要經過對齊填充來補全。

2.3.3 對象的訪問定位

  1. Java程序經過棧上的reference數據來操做堆上的具體對象。
  2. 不一樣虛擬機實現的對象訪問方式會有所不一樣,目前主流的訪問方式有兩種:使用句柄和直接指針。
  3. 使用句柄 是間接訪問,優勢是reference中存儲的是穩定的句柄地址,對象移動時只會改變句柄中的實例數據指針。
  4. 使用直接指針 是直接訪問,優勢就是速度快。

最後上一張本章結構圖

圖片來源於網絡若有侵權請私信刪除

圖片描述

《深刻理解Java虛擬機:JVM高級特性與最佳實踐_周志明.高清掃描版.pdf》佈局

下載地址:連接:http://pan.baidu.com/s/1miBQCBY 密碼:9kbn性能

推薦閱讀

《深刻理解Java虛擬機》(一)Java虛擬機發展史

《深刻理解Java虛擬機》(二)Java虛擬機運行時數據區

《深刻理解Java虛擬機》(三)垃圾收集器與內存分配策略

《深刻理解Java虛擬機》(四)虛擬機性能監控與故障處理工具

《深刻理解Java虛擬機》(五)JVM調優 - 工具

《深刻理解Java虛擬機》(六)堆內存使用分析,GC 日誌解讀

Contact

  • 做者:鵬磊
  • 出處:http://www.ymq.io
  • Email:admin@souyunku.com
  • 版權歸做者全部,轉載請註明出處
  • Wechat:關注公衆號,搜雲庫,專一於開發技術的研究與知識分享

關注公衆號-搜雲庫

相關文章
相關標籤/搜索