Klass与Oop

Posted 大诚挚

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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++的好感真是倍增。

以上是关于Klass与Oop的主要内容,如果未能解决你的问题,请参考以下文章

jvm源码解读--15 oop对象详解

JVM中如何存储对象和类

JVM中如何存储对象和类

Hotspot对象的内存布局

Java对象模型

HSDB: 16张图带你看见JVM中的Java对象