【JVM從小白學成大佬】6.建立對象及對象的訪問定位

《JVM從小白學成大佬》系列推出到如今,收到了不少小夥伴的好評,也收到了一些小夥伴的建議,在此表示感謝。java

有幾個小夥伴提出了但願出一篇介紹對象的建立及訪問,猿人谷向來是沒有原則的,小夥們要求啥,咱就盡力知足,畢竟文章就是對本身學習的一個總結及和各位小夥伴交流學習的機會。話很少說,直接開擼!數組

1 建立對象

在Java程序運行過程當中無時無刻都有對象被建立出來,java中對象能夠採用new或反射或clone或反序列化的方法建立。接下來咱們咱們介紹在虛擬機中,對象(限於普通Java對象,不包括數組和Class對象等)的建立過程。緩存

字節碼new表示建立對象,虛擬機遇到該指令時,從棧頂取得目標對象在常量池中的索引,接着定位到目標對象的類型。接下來,虛擬機將根據該類的狀態,採起相應的內存分配技術,在內存中分配實例空間,並完成實例數據和對象頭的初始化。這樣,一個對象就在JVM中建立好了。安全

實例的建立過程,首先根據從類常量池中獲取對象類型信息並驗證類是否已被解析過,若確保該類已被加載和正確解析,使用快速分配(fast allocation)技術爲該類分配對象空間;若該類還沒有解析過,則只能經過慢速分配(slow allocation)方式分配實例對象。實例的建立流程以下圖所示。框架

對象建立過程.png

對象建立的基本流程:

  1. 驗證類已被解析。
  2. 獲取instanceKlass,確保Klass已徹底初始化。
  3. 若知足快速分配條件,則進入快速分配流程。
  4. 若不知足快速分配條件,或者快速分配失敗,則進入慢速分配流程。

1.1 快速分配

若是在實例分配以前已經完成了類型的解析,那麼分配操做僅僅是在內存空間中劃分可用內存,所以能以較高效率實現內存分配,這就是快速分配oop

根據分配空間是來自於線程私有區域仍是共享的堆空間,快速分配能夠分爲兩種空間選擇策略。HotSpot經過線程局部分配緩存技術(Thread-Local Allocation Buffers,即TLABs)能夠在線程私有區域實現空間的分配。佈局

能夠經過VM選項UseTLAB來開啓或關閉TLAB功能。學習

根據是否使用TLAB,快速分配方式有兩種選擇策略:線程

  • 選擇TLAB:首先嚐試在TLAB中分配,由於TLAB是線程私有區域,故不須要加鎖便可以確保線程安全。在分配一個新的對象空間時,將首先嚐試在TLAB空間中分配對象空間,若分配空間的請求失敗,則再嘗試使用加鎖機制在Eden區分配對象。
  • 選擇Eden空間:若失敗,則嘗試在共享的Eden區進行分配,Eden區是全部線程共享區域,須要保證線程安全,故採用原子操做進行分配。若分配失敗,則再次嘗試該操做,直到分配成功爲止。

實例空間分配成功之後,將對實例進行初始化。待完成對象的空間分配和初始化後,就能夠設置棧頂對象引用。固然,對象的空間分配和初始化操做都是基於從類常量池中獲取對象類型並確保該類已被加載和正確解析的前提下進行的,若是類未被解析,則須要進行慢速分配。3d

1.2 慢速分配

之因此成爲慢速分配,正是由於在分配實例前須要對類進行解析,確保類及依賴類已獲得正確的解析和初始化。慢速分配是調用InterpreterRuntime模塊_new()進行的,實現代碼以下。

// 確保要初始化的類不是抽象類型
klass->check_valid_for_instantiation(true, CHECK);
// 確保類已初始化
klass->initialize(CHECK);
// 分配實例
oop obj = klass->allocate_instance(CHECK);
// 在線程棧中設置對象引用
thread->set_vm_result(obj);

2 對象的訪問定位

創建對象是爲了使用對象,Java程序須要經過棧上的reference數據來操做上的具體對象。因爲reference類型在Java虛擬機規範中只規定了一個指向對象的引用,並無定義這個引用應該經過何種方式去定位、訪問堆中的對象的具體位置,因此對象訪問方式也是取決於虛擬機實現而定的。

目前主流的訪問方式有使用句柄直接指針兩種:

  • 若是使用句柄訪問的話,那麼Java堆中將會劃分出一塊內存來做爲句柄池,reference中存儲的就是對象的句柄地址,而句柄中包含了對象實例數據與類型數據各自的具體地址信息,以下圖所示。
    經過句柄訪問對象.png

  • 若是使用直接指針訪問,那麼Java堆對象的佈局中就必須考慮如何放置訪問類型數據的相關信息,而reference中存儲的直接就是對象地址。即便用直接指針訪問在對象被移動時reference自己須要被修改,reference存儲的就是對象地址。以下圖所示。
    經過直接指針訪問對象.png

這兩種對象訪問方式各有優點:

  • 使用句柄來訪問的最大好處就是reference中存儲的是穩定的句柄地址,在對象被移動(垃圾收集時移動對象時很是廣泛的行爲)時只會改變句柄中的實例數據指針,而reference自己不須要修改。
  • 使用直接指針訪問方式的最大好處就是速度更快,它節省了一次指針定位的時間開銷,因爲對象的訪問在Java中很是頻繁,所以這類開銷聚沙成塔後也是一項很是可觀的執行成本。

HotSpot就是使用第二種方式進行對象訪問的,但從整個軟件開發的範圍來看,各類語言和框架使用句柄來訪問的狀況也十分常見。

相關文章
相關標籤/搜索