HotSpot Oop/Klass 模型

基于:openjdk-8-src-b132-03_mar_2014

HotSpot JVM 没有将Java对象直接通过虚拟机映射到 C++ 对象,而是设计了一个 Oop/Klass 模型,其中 oop 为 Ordinary Object Pointer,用来表示对象的实例信息;klass 用来表示对象元数据信息,不是单指 Class 类的对象。

为什么要设计 Oop/Klass 这种二分模型的实现?
一个原因是不想让每个对象都包含 vtbl (虚方法表),其中 oop 中不含有任何虚函数,虚表只保存于 klass 中,可以进行 method dispatch(方法分派:动态)。

typedef class markOopDesc* markOop;
typedef class oopDesc* oop;
typedef class instanceOopDesc* instanceOop;

markOopDesc(hotspot\src\share\vm\oops\markOop.hpp)

The markOop describes the header of an object.
Note that the mark is not a real oop but just a word.

markOopDesc 描述的是对象头,它描述的不是一个真正的对象,而是一个字长的数据。在32为机器上,其大小为32位,在64位上为64位。
markOop 为指向 markOopDesc 的指针

oopDesc (hotspot\src\share\vm\oops\oop.hpp)是描述对象实例的基类,它是抽象类。并且不存在虚方法表。
oop 为指向 oopDesc 的指针

class instanceOopDesc : public oopDesc {}

An instanceOop is an instance of a Java Class
Evaluating “new HashTable()” will create an instanceOop.

instanceOopDesc 描述的是一个 JVM 层面的 Java 对象
instanceOop 为指向 instanceOopDesc 的指针


class oopDesc {
  friend class VMStructs;
 private:
  volatile markOop  _mark;
  union _metadata {
    Klass*      _klass;
    narrowKlass _compressed_klass;
  } _metadata;

oopDesc 对象包含两部分数据:_mark 和 _metadata;
1、_mark 是 markOop 类型对象,用于存储对象自身的运行时数据,如哈希码(HashCode)、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等等。
2、_metadata 是一个联合体,_klass 为指向 InstanceKlass 对象的指针;_compressed_klass 是一个压缩指针。在联合体中,各成员共享一段内存空间,一个联合变量的长度等于各成员中最长的长度。
1与2构成了Java对象的对象头。

VMStructs:This class is a friend of most classes, to be able to access private fields.


// An InstanceKlass is the VM level representation of a Java class.
// It contains all information needed for at class at execution runtime.

//  InstanceKlass layout:
//    [C++ vtbl pointer           ] Klass
//    [subtype cache              ] Klass
//    [instance size              ] Klass
//    [java mirror                ] Klass
//    [super                      ] Klass
//    [access_flags               ] Klass
//    [name                       ] Klass
//    [first subklass             ] Klass
//    [next sibling               ] Klass
//    [array klasses              ]
//    [methods                    ]
//    [local interfaces           ]
//    [transitive interfaces      ]
//    [fields                     ]
//    [constants                  ]
//    [class loader               ]
//    [source file name           ]
//    [inner classes              ]
//    [static field size          ]
//    [nonstatic field size       ]
//    [static oop fields size     ]
//    [nonstatic oop maps size    ]
//    [has finalize method        ]
//    [deoptimization mark bit    ]
//    [initialization state       ]
//    [initializing thread        ]
//    [Java vtable length         ]
//    [oop map cache (stack maps) ]
//    [EMBEDDED Java vtable             ] size in words = vtable_len
//    [EMBEDDED nonstatic oop-map blocks] size in words = nonstatic_oop_map_size
//      The embedded nonstatic oop-map blocks are short pairs (offset, length)
//      indicating where oops are located in instances of this klass.
//    [EMBEDDED implementor of the interface] only exist for interface
//    [EMBEDDED host klass        ] only exist for an anonymous class (JSR 292 enabled)

HotSpot VM 里,Klass 用于描述能被 GC 的对象的类型信息的元数据对象。而 Oop 则用来描述能被 GC 的 Java 对象。
当在 Java 中 new 一个对象时,本质是在堆内存创建一个 instanceOopDesc对象。instanceOopDesc 对象通过元数据指针(_klass或者_compressed_klass)指向方法区的元数据类型的信息(InstanceKlass )。

这里写图片描述

JVM可以通过对象引用准确定位到 Java 堆区中的 instanceOopDesc 对象,这样既可成功访问到对象的实例信息,当需要访问目标对象的具体类型时,JVM则会通过存储在 instanceOopDesc 中的元数据指针定位到存储在方法区中的 instanceKlass 对象上。

方法区是 JVM 的规范,不同虚拟机有不同的实现方式,我们常说的HotSpot虚拟机,它1.7版本实现方式就是永久代(PermGen),1.8版本是元空间(Metaspace)。

PermGen 是在 JVM 内存区内(not Heap),受到 JVM 内存限制制约。Metaspace 属于原生内存在 JVM 之外,基本上机器有多少内存就可以多大。


JVM 中,InstanceKlass、java.lang.Class的关系?
An InstanceKlass is the VM level representation of a Java class.
It contains all information needed for at class at execution runtime.

ClassFileParser 将 class 文件在 runtime 解析成一个个 InstanceKlass 对象,这个对象是静态字节码文件在运行时 Metaspace 空间的一个映射。我们知道Java是一种支持反射的语言,为了能在 Java 层实现对定义类型的解构,JVM实现了 InstanceKlass 的一个 java mirror 的概念——java.lang.Class 对象。
InstanceKlass类继承自Klass类,在Klass类中有一个成员变量,并且提供了相应的Setter/Getter函数实现:

// java/lang/Class instance mirroring this class
oop       _java_mirror;
oop java_mirror() const              { return _java_mirror; }
void set_java_mirror(oop m) { klass_oop_store(&_java_mirror, m); }             

在 java_lang_Class 类中,也提供了 Class 对象与 Klass 对象的转化函数:

static Klass* as_Klass(oop java_class);
static void set_klass(oop java_class, Klass* klass);

Class类所提供的反射机制,最终都是通过JNI接口,调用相应的native方法,然后通过 as_Klass 函数转换成 InstanceKlass 对象,拿到定义类型的元数据信息的。

实战下:

// -XX:+UseSerialGC -XX:-UseCompressedOops -Xms10m -Xmx10m
class Father {

}

class Son extends Father {
    private static final String COUNTRY = "China";
}

public class Main {
    public static void main(String[] args) {
        Son son = new Son();
    }
}
Microsoft Windows [版本 10.0.14393]
(c) 2016 Microsoft Corporation。保留所有权利。

E:\t00ls\Merry>jps
1504 RemoteMavenServer
10372
5108 Main
1016 Jps
5372 HSDB
8972 Launcher

E:\t00ls\Merry>java -cp .;%JAVA_HOME%/lib/sa-jdi.jar sun.jvm.hotspot.CLHSDB
hsdb> attach 5108
Attaching to process 5108, please wait...
hsdb> universe ::打印堆信息
Heap Parameters:
:: 新生代
Gen 0:   eden [0x0000000012c00000,0x0000000012c1ea18,0x0000000012eb0000) space capacity = 2818048, 4.452159792877907 used
  from [0x0000000012f00000,0x0000000012f4fff8,0x0000000012f50000) space capacity = 327680, 99.99755859375 used
  to   [0x0000000012eb0000,0x0000000012eb0000,0x0000000012f00000) space capacity = 327680, 0.0 usedInvocations: 1
::老年代
Gen 1:   old  [0x0000000012f50000,0x0000000012ff5ee0,0x0000000013600000) space capacity = 7012352, 9.69215464369159 usedInvocations: 0
:: 扫描 新生代 Eden 里面的 Son 对象
hsdb> scanoops 0x0000000012c00000 0x0000000012eb0000 test.Son
0x0000000012c14840 test/Son
Error: sun.jvm.hotspot.types.WrongTypeException: No suitable match for type of address 0x0000000012c14868
hsdb> whatis 0x0000000012c14840
Address 0x0000000012c14840: In thread-local allocation buffer for thread "main" (4)  [0x0000000012c111b8,0x0000000012c14850,0x0000000012c1ea00,{0x0000000012c1ea18})
:: 线程 TLAB 内分配的空间

hsdb> inspect 0x0000000012c14840
instance of Oop for test/Son @ 0x0000000012c14840 @ 0x0000000012c14840 (size = 16) :: 对象大小
_mark: 1
_metadata._klass: InstanceKlass for test/Son
hsdb> mem 0x0000000012c14840 2
0x0000000012c14840: 0x0000000000000001
0x0000000012c14848: 0x0000000013a12410 ::类型指针

hsdb> whatis 0x0000000013a12410
pointer to InstanceKlass
hsdb> inspect 0x0000000013a12410
Type is InstanceKlass (size of 440)
juint Klass::_super_check_offset: 56
Klass* Klass::_secondary_super_cache: Klass @ null
Array<Klass*>* Klass::_secondary_supers: Array<Klass*> @ 0x0000000013600f88
Klass* Klass::_primary_supers[0]: Klass @ 0x0000000013601c00
oop Klass::_java_mirror: Oop for java/lang/Class @ 0x0000000012c14718 Oop for java/lang/Class @ 0x0000000012c14718
jint Klass::_modifier_flags: 0
Klass* Klass::_super: Klass @ 0x0000000013a12208
Klass* Klass::_subklass: Klass @ null
jint Klass::_layout_helper: 16
Symbol* Klass::_name: Symbol @ 0x0000000014912ba0
AccessFlags Klass::_access_flags: 538968096
markOop Klass::_prototype_header: 5
Klass* Klass::_next_sibling: Klass @ null
u8 Klass::_trace_id: 38141952
Klass* InstanceKlass::_array_klasses: Klass @ null
Array<Method*>* InstanceKlass::_methods: Array<Method*> @ 0x0000000013a11f98
Array<Method*>* InstanceKlass::_default_methods: Array<Method*> @ null
Array<Klass*>* InstanceKlass::_local_interfaces: Array<Klass*> @ 0x0000000013600f88
Array<Klass*>* InstanceKlass::_transitive_interfaces: Array<Klass*> @ 0x0000000013600f88
Array<u2>* InstanceKlass::_fields: Array<u2> @ 0x0000000013a11f80
u2 InstanceKlass::_java_fields_count: 1
ConstantPool* InstanceKlass::_constants: ConstantPool @ 0x0000000013a11e88
ClassLoaderData* InstanceKlass::_class_loader_data: ClassLoaderData @ 0x0000000013edfab0
u2 InstanceKlass::_source_file_name_index: 16
char* InstanceKlass::_source_debug_extension: char @ null
Array<jushort>* InstanceKlass::_inner_classes: Array<jushort> @ 0x0000000013600f58
int InstanceKlass::_nonstatic_field_size: 0
int InstanceKlass::_static_field_size: 1
u2 InstanceKlass::_static_oop_field_count: 1
int InstanceKlass::_nonstatic_oop_map_size: 0
bool InstanceKlass::_is_marked_dependent: 0
u2 InstanceKlass::_minor_version: 0
u2 InstanceKlass::_major_version: 52
u1 InstanceKlass::_init_state: 4
Thread* InstanceKlass::_init_thread: Thread @ 0x000000000305e800
int InstanceKlass::_vtable_len: 5
int InstanceKlass::_itable_len: 2
u1 InstanceKlass::_reference_type: 0
OopMapCache* InstanceKlass::_oop_map_cache: OopMapCache @ null
JNIid* InstanceKlass::_jni_ids: JNIid @ 0x0000000014a15520
nmethod* InstanceKlass::_osr_nmethods_head: nmethod @ null
BreakpointInfo* InstanceKlass::_breakpoints: BreakpointInfo @ null
u2 InstanceKlass::_generic_signature_index: 0
jmethodID* InstanceKlass::_methods_jmethod_ids: jmethodID @ 0x0000000014a15480
u2 InstanceKlass::_idnum_allocated_count: 1
Annotations* InstanceKlass::_annotations: Annotations @ null
nmethodBucket* InstanceKlass::_dependencies: nmethodBucket @ null
Array<int>* InstanceKlass::_method_ordering: Array<int> @ 0x0000000013a12600
Array<int>* InstanceKlass::_default_vtable_indices: Array<int> @ null
hsdb>

这里写图片描述

class Model
{
    public static int a = 1;
    public int b;

    public Model(int b) {
        this.b = b;
    }
}

public static void main(String[] args) {
    int c = 10;
    Model modelA = new Model(2);
    Model modelB = new Model(3);
}

这里写图片描述


参考:
http://gao-xianglong.iteye.com/blog/2152345

https://www.jianshu.com/p/252e27863822

  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

N3verL4nd

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值