深入理解JVM虚拟机

Class 对象的理解

在JDK1.8完全废除永久代之前的JDK版本中,方法区是一个逻辑分区,实际是java堆的一部分,但是有Non-heap的标记,以便区分。
众所周知, java中new处的对象存放在java堆中,而对象的引用存放在虚拟机栈中。

Java中的Class也是一个类,所以Class对象也存放在堆当中,存放在方法区当中的是类的元数据,即类加载器从class文件中提取出来的类型信息、方法信息、字段信息等。
Java的对象(包括class对象)中保存着指向相应类的元数据的引用,元数据中又保存着指向class对象的引用

OOP-KLASS内存模型Class实例在堆中还是方法区中? - 小菜变大鸟 - 博客园
在JVM中,使用了OOP-KLASS模型来表示java对象。

JVM加载一个类的时候会创建一个instanceKlass,用来表示这个类的元数据,包括常量池、字段、方法等。存放在方法区。

在new一个对象时,jvm创建instanceOopDesc,来表示这个对象,存放在堆区,其引用,存放在栈区;平时说的Java Object Layout就是instanceOopDesc,它用来表示对象的实例信息;instanceOopDesc对应java中的对象实例。

HotSpot并没有把instanceKlass直接暴露给Java,而会另外创建对应的instanceOopDesc来表示java.lang.Class对象,并将后者称为前者的“Java镜像”,instanceKlass持有指向instanceOopDesc的引用。(_java_mirror便是该instanceKlass对Class对象的引用);S
instanceOopDesc包含三部分:

  1. 对象头,也叫Mark Word,主要存储对象运行时记录信息,如hashcode, GC分代年龄,锁状态标志,线程ID,时间戳等;
  2. 元数据指针,即指向方法区的instanceKlass实例
  3. 实例数据;
  4. 另外,如果是数组对象,还多了一个数组长度

总结:
instanceKlass保存类的元数据,存储在方法区,只有一份(同一个类加载器)。
instanceOopDesc保存类实例对象(包括class对象),存储在堆中。一个类的实例对象可以有多个,但class对象只有一个(同一个类加载器),一个类的class对象与其类的元数据一一对应。
instanceOopDesc中包含指向相应的instanceKlass(类的元数据)的指针,而instanceKlass又保存着相应class对象(instanceOopDesc)的引用。
HotSpot通过InstanceOopDesc将类的元数据通过class对象间接暴露给java,class对象是java访问类的元数据的入口(因为class对象(InstanceOopDesc)中保存着指向元数据的指针)。
Person类的实例(Oop)–>Person类的元数据()–>Person类的class对象:解读(前提:同一个类加载器)
每一个类的实例可以有多个,每个实例对象对应的Oop中对klass的引用都是同一个。
每一个类的元数据instanceKlass只有一个
每一个类的class对象(Oop)也只有一个
唯一的Klass与唯一的class对象一一对应,互相保存着对彼此的引用。
不同类加载器产生的class对象不同,分布在堆中的不同地址中。
这些引用关系支持着获取class对象三种方式的实现。
Class.forName(“ClassName”):通过类的元数据中的class对象引用获得class对象
object.getClass():通过实例对象中保存的对类的元数据的引用获取类的元数据(instanceKlass),通过instanceKlass中对class对象的引用获取class对象(instanceOopDesc)
ClassName.class:通过类的元数据中的class对象引用获得class对象
Oop中对klass的引用支持【通过class对象创建类的实例对象】这一功能的实现

原文链接:https://blog.csdn.net/weixin_44250483/article/details/121338111


你可能感兴趣的:(jvm,java,开发语言)