日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

Java虚拟机(二)对象的创建与OOP-Klass模型

發布時間:2025/3/21 java 20 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java虚拟机(二)对象的创建与OOP-Klass模型 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

相關文章?
Java虛擬機系列

前言
在前一篇文章中我們學習了Java虛擬機的結構原理與運行時數據區域,那么我們大概知道了Java虛擬機的內存的概況,那么內存中的數據是如何創建和訪問的呢?這篇文章會給你答案。

1.對象的創建
對象的創建通常是通過new一個對象而已,當虛擬機接收到一個new指令時,它會做如下的操作。?
(1)判斷對象對應的類是否加載、鏈接、初始化?
虛擬機接收到一條new指令時,首先會去檢查這個指定的參數是否能在常量池中定位到一個類的符號引用,并且檢查這個符號引用代表的類是否已被類加載器加載、鏈接和初始化過。如果沒有則先執行相應的類加載過程。關于類加載器我們在前一篇文章中已經提到過,這里不再贅述。

(2)為對象分配內存?
類加載完成后,接著會在Java堆中劃分一塊內存分配給對象。內存分配根據Java堆是否規整,有兩種方式:

指針碰撞:如果Java堆的內存是規整,即所有用過的內存放在一邊,而空閑的的放在另一邊。分配內存時將位于中間的指針指示器向空閑的內存移動一段與對象大小相等的距離,這樣便完成分配內存工作。
空閑列表:如果Java堆的內存不是規整的,則需要由虛擬機維護一個列表來記錄那些內存是可用的,這樣在分配的時候可以從列表中查詢到足夠大的內存分配給對象,并在分配后更新列表記錄。
Java堆的內存是否規整根據所采用的來及收集器是否帶有壓縮整理功能有關,關于垃圾收集器,本系列后面的文章會介紹。

(3)處理并發安全問題?
創建對象是一個非常頻繁的操作,所以需要解決并發的問題,有兩種方式:

對分配內存空間的動作進行同步處理,比如在虛擬機采用CAS算法并配上失敗重試的方式保證更新操作的原子性。
每個線程在Java堆中預先分配一小塊內存,這塊內存稱為本地線程分配緩沖(Thread Local Allocation Buffer)簡寫為TLAB,線程需要分配內存時,就在對應線程的TLAB上分配內存,當線程中的TLAB用完并且被分配到了新的TLAB時,這時候才需要同步鎖定。通過-XX:+/-UserTLAB參數來設定虛擬機是否使用TLAB。
(4)初始化分配到的內存空間?
將分配到的內存,除了對象頭都初始化為零值。

(5)設置對象的對象頭?
將對象的所屬類、對象的HashCode和對象的GC分代年齡等數據存儲在對象的對象頭中。

(6)執行init方法進行初始化?
執行init方法,初始化對象的成員變量、調用類的構造方法,這樣一個對象就被創建了出來。

2.對象的堆內存布局
對象創建完畢,并且已經在Java堆中分配了內存,那么對象在堆內存是如何進行布局的呢??
以HotSpot虛擬機為例,對象在堆內存的布局分為三個區域,分別是對象頭(Header)、實例數據(Instance Data)、對齊填充(Padding)。

對象頭:對象頭包括兩部分信息分別是Mark World和元數據指針,Mark World用于存儲對象運行時的數據,比如HashCode、鎖狀態標志、GC分代年齡等。而元數據指針用于指向方法區的中目標類的類型信息,通過元數據指針可以確定對象的具體類型。
實例數據:用于存儲對象中的各種類型的字段信息(包括從父類繼承來的)。
對齊填充:對齊填充不一定存在,起到了占位符的作用,沒有特別的含義。
對象的內存布局如下圖所示。?


3.HotSpot的對象模型
HotSpot中采用了OOP-Klass模型,它是用來描述Java對象實例的一種模型,OOP(Ordinary Object Pointer)指的是普通對象指針,而Klass用來描述對象實例的具體類型。?
HotSpot中,用instanceOopDesc 和 arrayOopDesc 來描述對象頭,其中arrayOopDesc對象用于描述數組類型。?
instanceOopDesc的代碼如下所示。?
openjdk/hotspot/src/share/vm/oops/instanceOop.hpp

class instanceOopDesc : public oopDesc {
?public:
? // aligned header size.
? static int header_size() { return sizeof(instanceOopDesc)/HeapWordSize; }

? // If compressed, the offset of the fields of the instance may not be aligned.
? static int base_offset_in_bytes() {
? ? // offset computation code breaks if UseCompressedClassPointers
? ? // only is true
? ? return (UseCompressedOops && UseCompressedClassPointers) ?
? ? ? ? ? ? ?klass_gap_offset_in_bytes() :
? ? ? ? ? ? ?sizeof(instanceOopDesc);
? }

? static bool contains_field_offset(int offset, int nonstatic_field_size) {
? ? int base_in_bytes = base_offset_in_bytes();
? ? return (offset >= base_in_bytes &&
? ? ? ? ? ? (offset-base_in_bytes) < nonstatic_field_size * heapOopSize);
? }
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
可以看出instanceOopDesc繼承自oopDesc:?
openjdk/hotspot/src/share/vm/oops/oop.hpp

class oopDesc {
? friend class VMStructs;
?private:
? volatile markOop ?_mark;
? union _metadata {
? ? Klass* ? ? ?_klass;
? ? narrowKlass _compressed_klass;
? } _metadata;

? // Fast access to barrier set. ?Must be initialized.
? static BarrierSet* _bs;
...
}
1
2
3
4
5
6
7
8
9
10
11
12
13
oopDesc中包含兩個數據成員:_mark 和 _metadata。其中markOop類型的_mark對象指的是前面講到的Mark World。_metadata是一個共用體,其中_klass是普通指針,_compressed_klass是壓縮類指針,它們就是前面講到的元數據指針,這兩個指針都指向instanceKlass對象,它用來描述對象的具體類型。?
instanceKlass的代碼如下所示。?
openjdk/hotspot/src/share/vm/oops/instanceKlass.hpp

class InstanceKlass: public Klass {
? ...
? enum ClassState {
? ? allocated, ? ? ? ? ? ? ? ? ? ? ? ? ?// allocated (but not yet linked)
? ? loaded, ? ? ? ? ? ? ? ? ? ? ? ? ? ? // loaded and inserted in class hierarchy (but not linked yet)
? ? linked, ? ? ? ? ? ? ? ? ? ? ? ? ? ? // successfully linked/verified (but not initialized yet)
? ? being_initialized, ? ? ? ? ? ? ? ? ?// currently running class initializer
? ? fully_initialized, ? ? ? ? ? ? ? ? ?// initialized (successfull final state)
? ? initialization_error ? ? ? ? ? ? ? ?// error happened during initialization
? };
? ...
?}?
1
2
3
4
5
6
7
8
9
10
11
12
instanceKlass繼承自Klass ,枚舉ClassState 用來標識對象的加載進度。?
知道了OOP-Klass模型,我們就可以分析Java虛擬機是如何通過棧幀中的對象引用找到對應的對象實例,如下圖所示。?


從圖中可以看出,通過棧幀中的對象引用找到Java堆中的instanceOopDesc對象,再通過instanceOopDesc中的元數據指針來找到方法區中的instanceKlass,從而確定該對象的具體類型。

參考資料?
《深入理解Java虛擬機》?
《JAVA虛擬機精講》?
深入探究 JVM | klass-oop 對象模型研究?
JVM源碼分析之Java對象的創建過程?
JVM源碼分析之Java類的加載過程
---------------------?
作者:劉望舒?
來源:CSDN?
原文:https://blog.csdn.net/itachi85/article/details/71159719?
?

總結

以上是生活随笔為你收集整理的Java虚拟机(二)对象的创建与OOP-Klass模型的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。