1. 程式人生 > >Java虛擬機器之物件的建立及記憶體佈局

Java虛擬機器之物件的建立及記憶體佈局

一、物件的建立

在語言層面上,物件的建立通常僅僅是一個new關鍵字而已,而當虛擬機器接收到一個new指令時,它會做如下的操作。

  1. 虛擬機器接收到一條new指令時,首先會去檢查這個指定的引數是否能在常量池中定位到一個類的符號引用,並且檢查這個符號引用代表的類是否已被類載入器載入、連結和初始化過。如果沒有則先執行相應的類載入過程。

  2. 類載入完成後,接著會在Java堆中劃分一塊記憶體分配給物件。記憶體分配根據Java堆是否規整,有兩種方式:(1)指標碰撞:如果Java堆的記憶體是規整,即所有用過的記憶體放在一邊,而空閒的的放在另一邊。分配記憶體時將位於中間的指標指示器向空閒的記憶體移動一段與物件大小相等的距離,這樣便完成分配記憶體工作。(2)空閒列表:如果Java堆的記憶體不是規整的,則需要由虛擬機器維護一個列表來記錄哪些記憶體是可用的,這樣在分配的時候可以從列表中查詢到足夠大的記憶體分配給物件,並在分配後更新列表記錄。

  3. 建立物件是一個非常頻繁的操作,所以需要解決併發的問題。而解決併發的問題有兩種方式:(1)對分配記憶體空間的動作進行同步處理,比如在虛擬機器採用CAS演算法並配上失敗重試的方式保證更新操作的原子性。(2)每個執行緒在Java堆中預先分配一小塊記憶體,這塊記憶體稱為本地執行緒分配緩衝(Thread Local Allocation Buffer)簡寫為TLAB,執行緒需要分配記憶體時,就在對應執行緒的TLAB上分配記憶體,當執行緒中的TLAB用完並且被分配到了新的TLAB時,這時候才需要同步鎖定。通過-XX:+/-UserTLAB引數來設定虛擬機器是否使用TLAB。

  4. 將分配到的記憶體,除了物件頭都初始化為零值。
  5. 將物件的所屬類、物件的HashCode和物件的GC分代年齡等資料儲存在物件的物件頭中。
  6. 執行init方法,初始化物件的成員變數、呼叫類的構造方法。

二、物件的記憶體佈局

在HotSpot虛擬機器中,物件在記憶體中儲存的佈局分為三個區域,分別是物件頭(Header)、例項資料(Instance Data)、對齊填充(Padding)。
(1)物件頭:物件頭包括兩部分資訊分別是Mark World和元資料指標,Mark World用於儲存物件執行時的資料,比如HashCode、鎖狀態標誌、GC分代年齡等。而元資料指標用於指向方法區的中目標類的型別資訊,通過元資料指標可以確定物件的具體型別。
(2)例項資料:用於儲存物件中的各種型別的欄位資訊(包括從父類繼承來的)。
(3)對齊填充:對齊填充不一定存在,起到了佔位符的作用,沒有特別的含義。

三、物件的訪問定位

建立物件是為了訪問物件,Java程式需要通過棧上的reference資料來操作堆上的具體物件。由於reference型別在Java虛擬機器規範中只規定了一個指向物件的引用,所以物件的訪問方式也是取決於虛擬機器的實現而定的。目前主流的訪問方式有二種:
(1)控制代碼訪問
使用控制代碼訪問時,Java堆將會劃出一塊記憶體來作為控制代碼池,reference中儲存的就是物件的控制代碼地址,而控制代碼中包含了物件例項資料和型別資料各自的具體資訊。具體如圖所示
控制代碼訪問
(2)直接指標訪問
如果使用直接指標訪問,Java堆物件的佈局中就必須考慮如何放置訪問型別資料的相關資訊,而reference中儲存的直接就是物件地址。
直接指標訪問

【參考資料】
《深入理解JVM虛擬機器》周志明 著

相關推薦

Java虛擬機器物件建立記憶體佈局

一、物件的建立 在語言層面上,物件的建立通常僅僅是一個new關鍵字而已,而當虛擬機器接收到一個new指令時,它會做如下的操作。 虛擬機器接收到一條new指令時,首先會去檢查這個指定的引數是否能在常量池中定位到一個類的符號引用,並且檢查這個符號引用代表的類是

深入理解Java虛擬機器物件

一.物件的建立 1.類載入檢查和分配記憶體 虛擬機器遇到一條new指令時,首先將去檢查這個指令的引數是否能在常量池中定位到一個類的符號引用,並且檢查這個符號引用代表的類是否已被載入、 解析和初始化過。 如果沒有,那必須先執行相應的類載入過程。 在類載入檢查通過後,接下來虛擬機器將為新生物

三、Java虛擬機器自動記憶體管理機制、物件建立記憶體分配

  1、物件是如何建立: 步驟:    (1)、虛擬機器遇到new <類名>的指令---->根據new的引數是否在常量池中定位一個類的符號引用    (2)、檢測該符號引用代表的類是否已經被載入、解析、和初始化。(如果沒有則

讀書筆記《深入理解Java虛擬機器》 (二)物件建立記憶體佈局、訪問定位

物件的建立 類載入檢查 檢查這個指令的引數是否能在常量池中定位到一個類的引用 檢查這個符號引用代表的類是否已被載入、解析和初始化過, 如果沒有,那必須先執行相應的類載入過程 確定物件所需記憶體的大小 為新生物件分配記憶體 初始化物件的欄位, 大

深入理解java虛擬機器自動記憶體管理機制(二)

垃圾收集演算法     java中的記憶體是交給虛擬機器管理的。要實現垃圾回收,必須考慮如下三個問題:     1. 哪些記憶體需要回收?     2. 什麼時候回收?     3. 怎麼回收?     對於第一點,往大了來說,是堆和方法區的記憶體需要回收。往具體了來說,是堆中哪些物件的記憶體可以回

深入理解java虛擬機器自動記憶體管理機制(三)

  各類垃圾收集器與GC日誌 (一)垃圾收集器   一、Serial收集器     最基本、歷史最悠久的收集器。使用複製演算法,用在新生代,通常老年代用Serial old配合。GC過程需要stop the world。適用於client模式下的虛擬機器。   二、ParNew收集器  

深入理解java虛擬機器自動記憶體管理機制(四)

記憶體分配與回收策略 (一)記憶體分配策略     給誰分配?分配到哪?是記憶體分配策略必須解答的問題。     java物件是分配的物件,往大方向來說,是分配到堆中,更細一點說,根據物件不同的特點分配到新生代和老年代區域。如果啟動了本地執行緒分配緩衝,就按執行緒優先在TLAB上分配。     一、新

深入理解Java虛擬機器筆記--物件記憶體佈局和訪問定位

物件的記憶體佈局         在HotSpot虛擬機器中,物件在記憶體中儲存的佈局可以分為3塊區域:物件頭(Header)、例項資料(Instance Data)和對齊填充(Padding)。         HotSpot虛擬機器物件頭包括兩部分資訊:第一

JVM(2)——HotSpot虛擬機器物件建立物件記憶體佈局物件的訪問定位

物件的建立 步驟1:檢查。虛擬機器遇到一條new指令時,首先將去檢查這個指令的引數是否能在常量池中定位到一個類的符號引用,並且檢查這個符號引用代表的類是否已被載入、解析和初始化過。如果沒有,那必須先執行相應的類載入過程。 步驟2:分記憶體。在類載入檢查通過後

JAVA虛擬機器物件建立過程

簡要說明的話,Java物件的建立過程分為下面幾步: 1、執行相關檢查; 2、為物件分配記憶體,將分配到的記憶體空間都初始化為零值; 3、進行構造程式碼塊和建構函式的初始化  下面詳細介紹這幾個步驟: 1、執行相關檢查 虛擬機器遇到一條new指令時,將會去檢查這個指令的引數是

Java虛擬機器(四)——物件建立、儲存和定位

物件的建立   Java是一門面向物件的程式語言,Java 程式執行過程中無時無刻都有物件被創建出來,在語言層面上,建立物件(例如克隆,反序列化)通常僅僅是一個new關鍵字而已,例如下面的語句。 Object obj = new Object(); 其實

Java虛擬機器自動記憶體管理機制

Java與C++之間有一堵由記憶體動態分配和垃圾收集技術所圍城的高牆,牆外面的人想進去,牆裡面的人卻想出來。Java憑藉虛擬機器自動記憶體管理機制,不需要為每一個new操作去配對free的操作,不容易出現記憶體洩露和記憶體溢位問題。但是我們還是很有必要了解虛擬機器是怎麼使用記

JAVA 虛擬機器記憶體管理(一)

JMM ( Java Memory Model )概要 如圖:為java執行時資料區,在程式執行過程中對記憶體的分配、垃圾的回收都在執行時資料區中進行。 方法區和堆被執行緒所共享(藍色區塊) JVM棧、本地方法棧、程式計數器為執行緒所獨享(綠色區塊)

Java虛擬機器記憶體區域

**原創文章,轉載請標明出處!https://www.cnblogs.com/boycelee/p/14095080.html** [toc] # 一、背景 相對於C/C++C程式設計師,Java程式設計師會相對輕鬆一些,因為Java虛擬機器的記憶體管理機制會管理記憶體,不需要開發人員手動進行記憶體管理,

Java虛擬機器‘靜態分派、動態分派’

Java是一門面向物件的語言,因為Java具備面向物件的三個特性:封裝、繼承、多型。分派的過程會揭示多型特性的一些最基本的體現,如“過載”和“重寫”在Java虛擬機器中是如何實現的,並不是語法上如何寫,我們關心的依然是虛擬機器如何確定正確的目標方法。 一、靜態分派 先看一段程式碼 pac

深入理解Java虛擬機器執行時資料區域

一.執行時資料區域有哪些? 首先,我們先來看一張圖: 如上面的圖所示,執行時記憶體區域主要分為:1.程式計數器,2.Java虛擬機器棧,3.本地方法棧,4.Java堆,5.方法區等等,下面就一個個來剖析一下。 二.這些區域都有哪些作用? 首先我們熟悉一下一個一般性的 Java 程式的

深入瞭解Java虛擬機器Java虛擬機器

        與程式計數器(想了解計數器看我上一篇部落格)一樣,Java虛擬機器棧也是執行緒私有的,他的生命週期與執行緒相同,虛擬機器棧描述的是Java方法執行的記憶體模式:每個方法在執行的同時都會建立一個棧幀用於儲存區域性變量表,運算元棧,動態連結,方法出

Java虛擬機器核心知識(二) JVM記憶體模型

說起記憶體,大家很容易就想到了記憶體溢位,對於Java工程獅來說,遇到OutOfMemory可以說是家常便飯了。在學習如何定位這些異常發生的原因並提出解決方案之前,我們必須瞭解一下,Java虛擬機器是如何劃分自己的記憶體區域的。 一. Java記憶體區域 一個

Java虛擬機器判斷物件存活的兩種方案:引用計數法與可達性分析演算法

java堆和方法區主要存放各種型別的物件(方法區中也儲存一些靜態變數和全域性常量等資訊),那麼我們在使用GC對其進行回收的時候首先要考慮的就是如何判斷一個物件是否應該被回收。也就是要判斷一個物件是否還有其他的引用或關聯使得這個物件處於存活的狀態。我們需要將不在存活狀態的所有物

深入理解Java虛擬機器——垃圾收集器與記憶體分配策略(讀書筆記)

判斷物件是否存活 1、引用計數法 給物件新增一個引用計數器,每當有一個地方引用它時,計數器值加1,當引用失效時,計數器值減1, 任何時刻計數器為0的物件就是不可能再被使用的。 缺點:不能解決物件之間迴圈引用的問題 2、根搜尋演算法(GC Roots Tracing)