JVM oop-klass模型

klass模型是指Java类在JVM中的存在形式,用来存储类的元信息如:常量池、属性信息、方法信息……

看下klass模型类的继承结构

从继承关系上也能看出来,类的元信息是存储在原空间的

普通的Java类在JVM中对应的是instanceKlass类的实例,再来说下它的三个字类

  1. InstanceMirrorKlass:用于表示java.lang.Class,Java代码中获取到的Class对象,实际上就是这个C++类的实例,存储在堆区,学名镜像类
  2. InstanceRefKlass:用于表示java/lang/ref/Reference类的子类
  3. InstanceClassLoaderKlass:用于遍历某个加载器加载的类

Java中的数组不是静态数据类型,是动态数据类型,即是运行期生成的,Java数组的元信息用ArrayKlass的子类来表示:

  1. TypeArrayKlass:用于表示基本类型的数组
  2. ObjArrayKlass:用于表示引用类型的数组

下面我们通过工具来看一段Java类的instanceKlass信息

public class Test {

    public static void main(String[] args) {
        
        while (true);
    }
}

 执行main方法 通过 jps -l 命令行找到Test 的进程号并通过jdk自带的工具HSDB 来查看该类的instanceKlass元信息
 我的进程号是 10056

D:\spring-boot\boot\target\classes>jps -l
23920 org.jetbrains.jps.cmdline.Launcher
10056 com.waf.boot.wk.Test
18076
18492 org.jetbrains.jps.cmdline.Launcher
23820 sun.jvm.hotspot.HSDB
25324 sun.tools.jps.Jps

通过cmd 运行 D:\java\jdk8\lib>java -cp .\sa-jdi.jar sun.jvm.hotspot.HSDB 命令打开HSDB工具 输入 进程号

找到 该对象的内存地址 

通过内存地址查看instanceKlass 元信息

以上就是这个对象在jvm中的instanceKlass的元信息(_layout_helper:16  空对象,16B为对象大小,8字节对齐)

ArrayKlass
改下代码 在main方法里面加入两个数组,一个基础类型的数组,一个引用类型的数组,通过jclasslib来看看编译后的信息
 

    public static void main(String[] args) {
        int[] i_arr = new int[1];
        String[] s_arr = new String[1];
        while (true);
    }

在main方法的字节码中有newarray 和 anewarray 两个数组 一个int(基本类型)一个String(引用类型)
JVM 字节码指令里面也有备注说明

当然也可以使用HSDB工具来查看 (注意是看main方法里面的)下面通过进程号开启HSDB工具

分别通过这两个内存地址查看instanceKlass 元信息
int[] 0x00000007160d43a8 String[] 0x00000007160d4398

 

oop(ordinary  object  pointer)

定义 比如:Class a = new ClassA(); 

当Hotspot执行到这里时,会先将 ClassA 这个类型加载到 perm 区 ( 也叫方法区 ),然后在 Hotspot 堆中为其实例对象a开辟一块内存空间,存放实例数据。在 JVM加载ClassA到 perm 区时,JVM就会创建一个instanceKlass,instanceKlass中保存了 ClassA 这个 Java 类中所定义的一切信息,包括变量 、方法 、父类 、接 口、构造函数 、属性等,所以 instanceKlass 就是 ClassA这个Java类类型结构的对等体。而 instanceOop  这个“普通对象指针”对象中包含了一个指针,该指针就指向instanceKlass这个实例。在JVM实例化ClassA时,JVM又会在堆中创建一个instanceOop , instanceOop便是 ClassA 对象实例 a 在内存中的对等体,主要存储 ClassA 实例对象的成员变量。 其中,instanceOop 中有一个指针指向 instanceKlass ,通过这个指针,JVM便可以在运行期获取这个类实例对象的类元信息。

对象的内存布局

对象的内存大小,上面有提到过一个地方,16B的空对象。当然用HSDB也能看到,这边我们用jol-core包里面的api来看
openjdk 源码中 hotspot/src/share/vm/oops/markOop.hpp 这个文件也可以看到对象头里面的描述信息(32/64bit)

我们现在来看具体Java代码里面的(肯定是个16B的空对象)

对象在内存中就是这样布局的
    Mark Word  32/64bit   4/8B

    类型指针   Klass pointer
	指针压缩 开启/关闭    4/8B
              

    数组长度 如果这个对象不是数组/如果这个对象是数组,占0/4B
      一个数组最多有多少元素
      2的32次方 - 1


  实例数据 类的非静态属性,生成对象时就是实例数据比如对象属性
    如果是引用类型  指针压缩 开启/关闭    4/8B


  对齐填充

    Java中所有的对象大小都是8字节对齐   8的整数倍
      如果一个对象占30B + JVM底层会补2B(对齐填充),凑成32字节,达到8字节对齐

 64bit Test:8B(Mark Word)+4B(开启指针压缩)+0B(不是数组)+0B(没有属性)=12B+4B(对其填充)=16B

指针压缩属性 jdk1.6后默认开启的

普通对象

64bit Test:8B(Mark Word)+4B(开启指针压缩)+0B(不是数组)+4B^2(有属性)=20B+4B(对其填充)=24B


数组对象
 

 64bit Test:8B(Mark Word)+4B(开启指针压缩)+4B(是数组)+4B^3(有属性)=28B+4B(对其填充)=32B

猜你喜欢

转载自blog.csdn.net/qq_38108719/article/details/115167626