[In-depth understanding of multithreading] Java's object model (2)

The keyword method was briefly introduced in the previous article synchronized. Among them, the synchronized code block is implemented using monitorenterand monitorexittwo instructions, and the synchronized method ACC_SYNCHRONIZEDis implemented using tags. The next few articles will go deeper from the perspective of JVM source code, peeling synchronizedoff the veil layer by layer.

Before entering the topic, there must be some basic knowledge that needs to be paved, so let's take a look at an easily overlooked but very important knowledge point - the Java object model.

As we all know, Java objects are kept in heap memory. In memory, a Java object contains three parts: object header, instance data and alignment padding. The object header is a very critical part, because the object header contains the lock status flag, the lock held by the thread and other flags . This article mainly starts with the Java object model, and finds out how the object header of our relationship and the runtime data related to the lock in the object header are represented in the JVM.

Java Object Model

Anyone who has come into contact with Java knows that Java is an object-oriented language. In the process of learning Java, you must be familiar with the following two sentences:

  • 1. In object-oriented software, an object is an instance of a class.

  • 2. Everything is an object

We also know that in the memory structure of the JVM, objects are stored in heap memory, and when we operate on objects, we actually operate on object references. So what is the structure of the object itself in the JVM? All analyses in this article are based on the HotSpot virtual machine.

open-class model

HotSpot is implemented based on C++, and C++ is an object-oriented language, which itself has the basic characteristics of object-oriented, so the object representation in Java, the easiest way is to generate a C++ class for each Java class corresponding to it. But the HotSpot JVM didn't do that and designed one OOP-Klass Model. OOP ( Ordinary Object Pointer) refers to the ordinary object pointer, and is Klassused to describe the concrete type of the object instance.

Why did HotSpot design a set oop-klass model? The answer is: the designers of the HotSopt JVM did not want to have one in every object vtable(virtual function table)

This explanation seems to make sense. As we all know, C++ and Java are both object-oriented languages, and an important feature of object-oriented languages ​​is polymorphism. Regarding the implementation of polymorphism, C++ and Java have essential differences.

Polymorphism is one of the most important features of object-oriented. It is a dynamic binding of methods, and the type of the implementation determines the behavior of the object at runtime. The manifestation of polymorphism is that the parent class pointer or reference points to the subclass object, and the method invoked on this pointer uses the implementation version of the subclass. Polymorphism is the key to the realization of IOC and template pattern.

In C++, polymorphism is implemented by means of virtual function tables. Each class containing virtual functions has a virtual function table (virtual table), and there is a pointer to the virtual function table at the top of the address space of this class object. pointer. In the virtual function table, all virtual functions are listed in the order in which they are declared. Since C++ does not maintain type information at runtime, the method overridden by the subclass is replaced directly in the virtual function table of the subclass at compile time.

In Java, type information and class inheritance are maintained at runtime. Each class will correspond to a data structure in the method area for storing class information, and this data structure can be accessed through the Class object. Among them, the type information has the superclass attribute to indicate its superclass, and the method table corresponding to this class (which only contains the methods defined by this class, excluding those inherited from the superclass). And each object created on the heap has a pointer to the data structure of the type information of the method area, through which the type of the object can be determined.

The above paragraph is taken from the Internet, and it makes some sense, but it is not entirely correct. As for why, I will elaborate on it later when I introduce Klass.

The overall definition of the opp-klass model can be found in the source code of HotSpot.

The oops module can be divided into two relatively independent parts: the OOP framework and the Klass framework.

The respective systems of oop and klass are defined in oopsHierarchy.hpp.

oop


oop system

//定义了oops共同基类
typedef class   oopDesc*                            oop;
//表示一个Java类型实例
typedef class   instanceOopDesc*            instanceOop;
//表示一个Java方法
typedef class   methodOopDesc*                    methodOop;
//表示一个Java方法中的不变信息
typedef class   constMethodOopDesc*            constMethodOop;
//记录性能信息的数据结构
typedef class   methodDataOopDesc*            methodDataOop;
//定义了数组OOPS的抽象基类
typedef class   arrayOopDesc*                    arrayOop;
//表示持有一个OOPS数组
typedef class   objArrayOopDesc*            objArrayOop;
//表示容纳基本类型的数组
typedef class   typeArrayOopDesc*            typeArrayOop;
//表示在Class文件中描述的常量池
typedef class   constantPoolOopDesc*            constantPoolOop;
//常量池告诉缓存
typedef class   constantPoolCacheOopDesc*   constantPoolCacheOop;
//描述一个与Java类对等的C++类
typedef class   klassOopDesc*                    klassOop;
//表示对象头
typedef class   markOopDesc*                    markOop;

Listed above is the composition structure of the entire Oops module, which contains multiple sub-modules. Each submodule corresponds to a type, and the OOP of each type represents the type of a specific object used inside the JVM.

从上面的代码中可以看到,有一个变量opp的类型是oppDesc ,OOPS类的共同基类型为oopDesc

class oopDesc {
  friend class VMStructs;
 private:
  volatile markOop  _mark;
  union _metadata {
    wideKlassOop    _klass;
    narrowOop       _compressed_klass;
  } _metadata;
}

在Java程序运行过程中,每创建一个新的对象,在JVM内部就会相应地创建一个对应类型的OOP对象。在HotSpot中,根据JVM内部使用的对象业务类型,具有多种oopDesc的子类。除了oppDesc类型外,opp体系中还有很多instanceOopDescarrayOopDesc 等类型的实例,他们都是oopDesc的子类。


这些OOPS在JVM内部有着不同的用途,例如instanceOopDesc表示类实例,arrayOopDesc表示数组。也就是说,当我们使用new创建一个Java对象实例的时候,JVM会创建一个instanceOopDesc对象来表示这个Java对象。同理,当我们使用new创建一个Java数组实例的时候,JVM会创建一个arrayOopDesc对象来表示这个数组对象。

在HotSpot中,oopDesc类定义在oop.hpp中,instanceOopDesc定义在instanceOop.hpp中,arrayOopDesc定义在arrayOop.hpp中。

简单看一下相关定义:

class instanceOopDesc : public oopDesc {
}

class arrayOopDesc : public oopDesc {
}

通过上面的源码可以看到,instanceOopDesc实际上就是继承了oopDesc,并没有增加其他的数据结构,也就是说instanceOopDesc中包含两部分数据:markOop _markunion _metadata

这里的markOop你可能又熟悉了,这不就是OOPS体系中的一部分吗,上面注释中已经说过,他表示对象头。 _metadata是一个联合体,这个字段被称为元数据指针。指向描述类型Klass对象的指针。

HotSpot虚拟机中,对象在内存中存储的布局可以分为三块区域:对象头、实例数据和对齐填充。在虚拟机内部,一个Java对象对应一个instanceOopDesc的对象,该对象中有两个字段分别表示了对象头和实例数据。那就是_mark_metadata

文章开头我们就说过,之所以我们要写这篇文章,是因为对象头中有和锁相关的运行时数据,这些运行时数据是synchronized以及其他类型的锁实现的重要基础。因为本文主要介绍的oop-klass模型,在这里暂时不对对象头做展开,下一篇文章介绍。

前面介绍到的_metadata是一个共用体,其中_klass是普通指针,_compressed_klass是压缩类指针。在深入介绍之前,就要来到oop-Klass中的另外一个主角klass了。

klass

klass体系 

//klassOop的一部分,用来描述语言层的类型
class  Klass;
//在虚拟机层面描述一个Java类
class   instanceKlass;
//专有instantKlass,表示java.lang.Class的Klass
class     instanceMirrorKlass;
//专有instantKlass,表示java.lang.ref.Reference的子类的Klass
class     instanceRefKlass;
//表示methodOop的Klass
class   methodKlass;
//表示constMethodOop的Klass
class   constMethodKlass;
//表示methodDataOop的Klass
class   methodDataKlass;
//最为klass链的端点,klassKlass的Klass就是它自身
class   klassKlass;
//表示instanceKlass的Klass
class     instanceKlassKlass;
//表示arrayKlass的Klass
class     arrayKlassKlass;
//表示objArrayKlass的Klass
class       objArrayKlassKlass;
//表示typeArrayKlass的Klass
class       typeArrayKlassKlass;
//表示array类型的抽象基类
class   arrayKlass;
//表示objArrayOop的Klass
class     objArrayKlass;
//表示typeArrayOop的Klass
class     typeArrayKlass;
//表示constantPoolOop的Klass
class   constantPoolKlass;
//表示constantPoolCacheOop的Klass
class   constantPoolCacheKlass;

oopDesc是其他oop类型的父类一样,Klass类是其他klass类型的父类。


Klass向JVM提供两个功能:

  • 实现语言层面的Java类(在Klass基类中已经实现)

  • 实现Java对象的分发功能(由Klass的子类提供虚函数实现)

文章开头的时候说过:之所以设计oop-klass模型,是因为HotSopt JVM的设计者不想让每个对象中都含有一个虚函数表。

HotSopt JVM的设计者把对象一拆为二,分为klassoop,其中oop的职能主要在于表示对象的实例数据,所以其中不含有任何虚函数。而klass为了实现虚函数多态,所以提供了虚函数表。所以,关于Java的多态,其实也有虚函数的影子在。

_metadata是一个共用体,其中_klass是普通指针,_compressed_klass是压缩类指针。这两个指针都指向instanceKlass对象,它用来描述对象的具体类型。

instanceKlass

JVM在运行时,需要一种用来标识Java内部类型的机制。在HotSpot中的解决方案是:为每一个已加载的Java类创建一个instanceKlass对象,用来在JVM层表示Java类。

来看下instanceKlass的内部结构:

  //类拥有的方法列表
  objArrayOop     _methods;
  //描述方法顺序
  typeArrayOop    _method_ordering;
  //实现的接口
  objArrayOop     _local_interfaces;
  //继承的接口
  objArrayOop     _transitive_interfaces;
  //域
  typeArrayOop    _fields;
  //常量
  constantPoolOop _constants;
  //类加载器
  oop             _class_loader;
  //protected域
  oop             _protection_domain;
      ....

可以看到,一个类该具有的东西,这里面基本都包含了。

这里还有个点需要简单介绍一下。

在JVM中,对象在内存中的基本存在形式就是oop。那么,对象所属的类,在JVM中也是一种对象,因此它们实际上也会被组织成一种oop,即klassOop。同样的,对于klassOop,也有对应的一个klass来描述,它就是klassKlass,也是klass的一个子类。klassKlass作为oop的klass链的端点。关于对象和数组的klass链大致如下图:


在这种设计下,JVM对内存的分配和回收,都可以采用统一的方式来管理。oop-klass-klassKlass关系如图:


内存存储

关于一个Java对象,他的存储是怎样的,一般很多人会回答:对象存储在堆上。稍微好一点的人会回答:对象存储在堆上,对象的引用存储在栈上。今天,再给你一个更加显得牛逼的回答:

对象的实例(instantOopDesc)保存在堆上,对象的元数据(instantKlass)保存在方法区,对象的引用保存在栈上。

其实如果细追究的话,上面这句话有点故意卖弄的意思。因为我们都知道。方法区用于存储虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。 所谓加载的类信息,其实不就是给每一个被加载的类都创建了一个 instantKlass对象么。

talk is cheap ,show me the code 

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);
}

存储结构如下:


总结

每一个Java类,在被JVM加载的时候,JVM会给这个类创建一个instanceKlass,保存在方法区,用来在JVM层表示该Java类。当我们在Java代码中,使用new创建一个对象的时候,JVM会创建一个instanceOopDesc对象,这个对象中包含了两部分信息,方法头以及元数据。对象头中有一些运行时数据,其中就包括和多线程相关的锁的信息。元数据其实维护的是指针,指向的是对象所属的类的instanceKlass


Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325439747&siteId=291194637