前段時間,一直在看《Hotspot實戰》,順便編譯了一份OpenJDK的源碼,而後就在eclipse裏面調試起來。c++
雖然個人入門語言是c/c++,可是被Java拉過來好幾年了,如今再看源碼,熟悉又陌生,好在慢慢找到了感受。數據結構
這是分析Hotspot源碼的第一篇,講一下Klass和Oop這兩種數據結構。eclipse
系統的介紹和講解,能夠查看https://yq.aliyun.com/articles/20279和http://www.jianshu.com/p/252e27863822這兩篇文章。確實寫的比較好,深刻並且透徹。另外能夠再看看《Hotspot實戰》的第3章。oop
我這裏主要看看Klass和Oop的內存佈局。佈局
當時看這張圖的時候,有一個巨大的疑問,instanceKlass的數據結構與圖不符,沒有對象頭(Mark和Klass這兩個屬性)。this
真是百思不得其解。spa
因而,繼續看源碼。指針
1)對象頭裏的Klass這個屬性,是一個klassOopDesc類型的指針,並非一個指向Klass類的指針。why???調試
看了以前的第一篇文章,豁然開朗。在JDK8以前,方法區內的描述類型的元數據對象,也是由GC管理的。全部由GC統一管理的對象,都要繼承自oopDesc,因此纔會誕生klassOopDesc這個類型。從JDK8開始,類型元數據都移出了GC堆,因此Klass這個屬性能夠直接指向Klass類了。code
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++的好感真是倍增。