溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Java中New一個(gè)對(duì)象是個(gè)怎么樣的過程

發(fā)布時(shí)間:2021-12-09 17:12:34 來源:億速云 閱讀:164 作者:柒染 欄目:大數(shù)據(jù)

這篇文章將為大家詳細(xì)講解有關(guān)Java中New一個(gè)對(duì)象是個(gè)怎么樣的過程,文章內(nèi)容質(zhì)量較高,因此小編分享給大家做個(gè)參考,希望大家閱讀完這篇文章后對(duì)相關(guān)知識(shí)有一定的了解。

在語(yǔ)言層面創(chuàng)建對(duì)象(例如克隆、反序列化)通常僅僅是一個(gè)new關(guān)鍵字而已,而在虛擬機(jī)中,對(duì)象(普通Java對(duì)象,不包括數(shù)組和Class對(duì)象等)的創(chuàng)建時(shí)一個(gè)怎么樣的過程?

一、對(duì)象的創(chuàng)建

當(dāng)虛擬機(jī)遇到一條new指令時(shí)候,首先去檢查這個(gè)指令的參數(shù)是否能在常量池中能否定位到一個(gè)類的符號(hào)引用,并且檢查這個(gè)符號(hào)引用代表的類是否已被加載、解析和初始化過。如果沒有,那必須先執(zhí)行相應(yīng)的類加載過程。

在類加載檢查通過后,接下來虛擬機(jī)將為新生的對(duì)象分配內(nèi)存。對(duì)象所需的內(nèi)存的大小在類加載完成后便可以完全確定,為對(duì)象分配空間的任務(wù)等同于把一塊確定大小的內(nèi)存從Java堆中劃分出來,目前常用的有兩種方式:

1.指針碰撞(Bump the Pointer):假設(shè)Java堆的內(nèi)存是絕對(duì)規(guī)整的,所有用過的內(nèi)存都放一邊,空閑的內(nèi)存放在另一邊,中間放著一個(gè)指針作為分界點(diǎn)的指示器,那所分配內(nèi)存就僅僅把那個(gè)指針向空閑空間那邊挪動(dòng)一段與對(duì)象大小相等的距離。

2.空閑列表(Free List):如果Java堆中的內(nèi)存并不是規(guī)整的,已使用的內(nèi)存和空間的內(nèi)存是相互交錯(cuò)的,虛擬機(jī)必須維護(hù)一個(gè)空閑列表,記錄上哪些內(nèi)存塊是可用的,在分配時(shí)候從列表中找到一塊足夠大的空間劃分給對(duì)象使用。

除了如何劃分可用空間外,在并發(fā)情況下劃分不一定是線程安全的,有可能出現(xiàn)正在給A對(duì)象分配內(nèi)存,指針還沒有來得及修改,對(duì)象B又同時(shí)使用了原來的指針分配內(nèi)存的情況,解決這個(gè)問題兩種方案:

  1. 分配內(nèi)存空間的動(dòng)作進(jìn)行同步處理:實(shí)際上虛擬機(jī)采用CAS配上失敗重試的方式保證了更新操作的原子性。

  2. 內(nèi)存分配的動(dòng)作按照線程劃分在不同的空間中進(jìn)行:為每個(gè)線程在Java堆中預(yù)先分配一小塊內(nèi)存,稱為本地線程分配緩沖(Thread Local Allocation Buffer, TLAB)。

內(nèi)存分配完后,虛擬機(jī)需要將分配到的內(nèi)存空間中的數(shù)據(jù)類型都初始化為零值(不包括對(duì)象頭);接下來虛擬機(jī)要對(duì)對(duì)象進(jìn)行必要的設(shè)置,例如這個(gè)對(duì)象是哪個(gè)類的實(shí)例、如何才能找到類的元數(shù)據(jù)信息、對(duì)象的哈希碼、對(duì)象的GC分代年齡等信息,這些信息都存放在對(duì)象的對(duì)象頭中。

做完以上以后,從虛擬機(jī)視角來看,一個(gè)新的對(duì)象已經(jīng)產(chǎn)生了,但是Java程序視角來看,執(zhí)行new操作后會(huì)接著執(zhí)行方法,把對(duì)象按照程序員的意愿進(jìn)行初始化,這樣一個(gè)真正的對(duì)象就產(chǎn)生了。

二、對(duì)象的內(nèi)存布局

在HotSpot虛擬機(jī)中,對(duì)象在內(nèi)存中的存儲(chǔ)的布局可以分為3塊區(qū)域:對(duì)象頭(Header)、實(shí)例數(shù)據(jù)(Instance Data)和對(duì)齊填充(Padding).

(一)對(duì)象頭

1.第一部分用于存儲(chǔ)對(duì)象自身的運(yùn)行時(shí)數(shù)據(jù),如哈希碼、GC分代年齡、鎖狀態(tài)標(biāo)志、線程持有的鎖、偏向線程ID、偏向時(shí)間戳等,官方稱為“Mark Word”。

2.類型指針,即對(duì)象指向它的類元數(shù)據(jù)的指針,虛擬機(jī)通過這個(gè)指針來確定這個(gè)對(duì)象的哪個(gè)實(shí)例。面試:100道Java中高級(jí)面試題匯總+詳細(xì)拆解

(二)實(shí)例數(shù)據(jù)

對(duì)象真正存儲(chǔ)的有效信息,也是在程序代碼中所定義的各種類型的字段內(nèi)容。

(三)對(duì)齊填充

對(duì)齊填充不是必然存在的,也沒有特別的含義,僅僅起著占位符的作用。

三、對(duì)象的訪問定位

建立對(duì)象是為了使用對(duì)象,我們的Java程序需要通過棧上的reference數(shù)據(jù)來操作堆上的具體對(duì)象。目前主流訪問方式有使用句柄和直接指針兩種:

(一)句柄訪問

Java堆中將會(huì)劃分出一塊內(nèi)存來作為句柄池,reference中存儲(chǔ)的就是對(duì)象句柄位置,而句柄中包含了對(duì)象實(shí)例數(shù)據(jù)與類型數(shù)據(jù)各自的具體地址信息。

Java中New一個(gè)對(duì)象是個(gè)怎么樣的過程

(二)直接指針訪問

如果使用直接指針訪問,那么Java堆對(duì)象的布局中就必須考慮如何放置訪問類型數(shù)據(jù)的相關(guān)信息,而reference中存儲(chǔ)的直接就是對(duì)象地址。

Java中New一個(gè)對(duì)象是個(gè)怎么樣的過程

關(guān)于Java中New一個(gè)對(duì)象是個(gè)怎么樣的過程就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,可以學(xué)到更多知識(shí)。如果覺得文章不錯(cuò),可以把它分享出去讓更多的人看到。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI