Klass與Oop


前段時間,一直在看《Hotspot實戰》,順便編譯了一份OpenJDK的源碼,然后就在eclipse里面調試起來。

雖然我的入門語言是c/c++,但是被Java拉過來好幾年了,現在再看源碼,熟悉又陌生,好在慢慢找到了感覺。

這是分析Hotspot源碼的第一篇,講一下Klass和Oop這兩種數據結構。

系統的介紹和講解,可以查看https://yq.aliyun.com/articles/20279和http://www.jianshu.com/p/252e27863822這兩篇文章。確實寫的比較好,深入而且透徹。另外可以再看看《Hotspot實戰》的第3章。

我這里主要看看Klass和Oop的內存布局。

 

當時看這張圖的時候,有一個巨大的疑問,instanceKlass的數據結構與圖不符,沒有對象頭(Mark和Klass這兩個屬性)。

真是百思不得其解。

於是,繼續看源碼。

1)對象頭里的Klass這個屬性,是一個klassOopDesc類型的指針,並不是一個指向Klass類的指針。why???

看了之前的第一篇文章,豁然開朗。在JDK8之前,方法區內的描述類型的元數據對象,也是由GC管理的。所有由GC統一管理的對象,都要繼承自oopDesc,所以才會誕生klassOopDesc這個類型。從JDK8開始,類型元數據都移出了GC堆,所以Klass這個屬性可以直接指向Klass類了。

2)klassOopDesc只有從父類繼承過來的Mark和Klass這兩個屬性,並沒有指向Klass類的指針,那oop是如何找到對應的Klass的呢???

klassOopDesc內部有一個方法:klass_part()

 

  // returns the Klass part containing dispatching behavior
  Klass* klass_part() const                      { return (Klass*)((address)this + sizeof(klassOopDesc)); }

 

這個方法果然返回一個指向Klass的指針,但是計算過程比較詭異,在當前klassOopDesc對象的首地址增加sizeof(klassOopDesc)這么多空間后的地址。也就是說,一個klassOopDesc對象數據和對應的Klass對象數據,是從上到下緊密的排列着,有了klassOopDesc的指針,就能順藤摸瓜找到對應的Klass數據。

那當初構造的時候,是按這種模式在內存分配數據的嗎???

之前的第二篇文章,講的巨細。可以看到,在類加載的過程中,構造了一個空的Klass對象,然后調用了Klass類的as_klassOop方法返回klassOopDesc的指針。

  // returns the enclosing klassOop
  klassOop as_klassOop() const {
    // see klassOop.hpp for layout.
    return (klassOop) (((char*) this) - sizeof(klassOopDesc));
  }

klassOop是klassOopDesc指針的一個別名。構造的時候,首地址減去sizeof(klassOopDesc)這么多空間后的地址。這時候,內存空間是分配出來了,具體的數據,在后續過程中填充。

最后說下看源碼心得體會 :其實那張圖上的數據排列結構是對的,但是具體的實現方式,如果不看源碼肯定會很疑惑。另外,看到這么犀利的指針操作,對c/c++的好感真是倍增。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM