Klass与Oop

前段时间,一直在看《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++的好感真是倍增。

相关文章
相关标签/搜索