JAVA对象模型、对象头

JAVA对象模型、对象头

参考自:https://www.cnblogs.com/iou123lg/p/9190572.html

java虚拟机有很多对应的实现版本,这里的内容基于HotSpot虚拟机。HotSpot的底层是用C++ 实现的,可在源码确认。
我们都知道java和C++ 都是面向对象的语言,那么java在对象在虚拟机的表示,最简单一种实现就是在C++层面上实现一个与之对应的类,然而HotSpot并没有这么实现,而是专门设计了一套OOP-Klass二分模型。

OOP:ordinary object pointer,普通对象指针,用来描述兑现实例信息。
Klass:Java类的C++ 对等体,用来描述Java类。
之所以这么设计,其中一个理由是作者不想让每一个对象都有一个C++ 虚函数指针(vtable 虚函数表),下面是klass.hpp中的一段注释:

// One reason for the oop/klass dichotomy in the implementation is
// that we don't want a C++ vtbl pointer in every object.  ……….

对于OOP对象来说,主要职能是表示对象的实例信息,没必要持有任何虚函数;而在描述java类的Klass兑现中含有VTBL(继承自klass_vtbl),那么klass就可以根据java对象的实际类型进行C++ 的分发,这样OOP对象只需要通过相应的Klass便可找到所有的虚函数,就避免了给每一个对象都分配一个C++ 的虚函数指针。
深入理解多线程(二)—— Java的对象模型
Klass向JVM提供了两个功能:

  • 实现语言层面的java类;
  • 实现java对象的分发功能;
    这两个功能在一个C++ 类中就能实现,前者在Klass中已经实现,而后者就由Klass的子类提供虚函数实现(这是klass.hpp中的一段注释)
// A Klass provides:
//  1: language level class object (method dictionary etc.)
//  2: provide vm dispatch behavior for the object
// Both functions are combined into one C++ class.

OOP框架的关系可以在oopHierarchy.hpp文件中体现,JDK1.7和JDK1.8由于内存空间的变化(永久代?),所以oopsHierarchy.hpp的实现也不一样,这里以OpenJDK1.7开描述OOP-Klass。

typedef class oopDesc*                            oop;//oops基类
typedef class   instanceOopDesc*            instanceOop; //Java类实例
typedef class   methodOopDesc*                    methodOop; //Java方法
typedef class   constMethodOopDesc*            constMethodOop; //Java方法不变信息
typedef class   methodDataOopDesc*            methodDataOop; //性能信息数据结构
typedef class   arrayOopDesc*                    arrayOop; //数组oops基类
typedef class     objArrayOopDesc*            objArrayOop; //数组oops对象
typedef class     typeArrayOopDesc*            typeArrayOop;
typedef class   constantPoolOopDesc*            constantPoolOop;
typedef class   constantPoolCacheOopDesc*   constantPoolCacheOop;
typedef class   klassOopDesc*                    klassOop; //与Java类对等的C++类
typedef class   markOopDesc*                    markOop; //Java对象头
typedef class   compiledICHolderOopDesc*    compiledICHolderOop;

在java程序运行的过程中,每创建一个java对象,在JVM内部就会相应的创建一个OOP对象来表示该java对象。OOP对象的基类就是oopDesc,他的代码实现如下:

 volatile markOop  _mark;
  union _metadata {
    wideKlassOop    _klass;
    narrowOop       _compressed_klass;
  } _metadata;

在虚拟机内部,通过instanceOopDesc来表示一个Java对象。对象在内部中的布局可以分为两个连续的部分:

  • instanceOopDesc(对象头)
  • 实例数据
    instanceOopDesc又被称为对象头,继承自oopDesc,看看instanceOop.hpp的实现,未新增的数据结构,和oopDesc一样,包含如下两部分信息:

_mark : markOop类型,存储对象运行时记录信息,主要有HashCode、分代年龄、锁状态标记、线程持有的锁、偏向线程ID等,占用内存和虚拟机位长一致(32或64),如果是32位虚拟机则为32位,以此类推。详细看看JVM原理。

_metadata:联合体,指向描述类型的Klass对象的指针,因为Klass对象包含了实例对象所属类型的元数据,古被称为元数据指针。虚拟机运行时将频繁使用这个指针定位代方法区的类信息。

到此基本描述了java的对象头,但是这只是一部分,还有一分部是klass,合起来才是完整的对象类型。那么klass在对象模型中是如何体现的呢?实际上,HotSpot是这样处理数据的,通过为每一个已加载的java类创建一个instanceKlass对象,用来在JVM层表示java类。

这是instanceKlass的数据结构:

// Method array.方法列表
objArrayOop     _methods;
// Int array containing the original order of method in the class file (for
// JVMTI).方法顺序
typeArrayOop    _method_ordering;
// Interface (klassOops) this class declares locally to implement.实现接口
objArrayOop     _local_interfaces;
// Interface (klassOops) this class implements transitively.继承接口
objArrayOop     _transitive_interfaces;
…………
typeArrayOop    _fields;
// Constant pool for this class.
constantPoolOop _constants;
// Class loader used to load this class, NULL if VM loader used.
oop             _class_loader;
// Protection domain.
oop             _protection_domain;

可以看到,一个类该有的内容,instanceKlass基本都有了。

综上,java对象在JVM中的表示是:对象的实例(instanceOopDesc)存储在堆上,对象的元数据(instanceKlass)存储在方法区,对象的引用存储在栈上。如图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hVK8Gj5J-1573375977066)(https://note.youdao.com/yws/api/personal/file/6829DC58567E4DB996BB4DB72D2E79B8?method=download&shareKey=b04fe5a9ca95de952ed3774ed3c34918)]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值