jvm环境:openJdk15_20的hotspot
一、问题背景
当我们在java程序中,使用new创建一个对象时,是否考虑过或者知道这个对象在JVM中是如何表示的?它占用的内存大小是多少?
class A {
int a;
}
public static void main(String[] args) {
A a = new A();
}
二、Java对象模型-OOP-Klass
在JVM中,Hotspot并没有将Java对象映射成C++对象,而是实现了Java的对象模型(OOP-Klass),JVM不希望每个对象中都包含一份虚函数表(Why???待探究)。
那么为何要设计这样一个一分为二的对象模型呢?这是因为 HotSopt JVM 的设计者不想让每个对象中都含有一个 vtable(虚函数表),所以就把对象模型拆成 klass 和 oop,其中 oop 中不含有任何虚函数,而 klass 就含有虚函数表,可以进行 method dispatch。这个模型其实是参照的 Strongtalk VM 底层的对象模型。
下面解释下OOP-Kclass模型的定义:
- OOP 英文全程是Ordinary Object Pointe,即普通对象指针,看起来像个指针实际上是藏在指针里的对象,表示对象的实例信息。
- Klass 元数据和方法信息,用来描述 Java。是Java类的在C++中的表示形式,用来描述Java类的信息。
当加载一个Class时,会创建一个InstanceKlass对象,实例化的对象则对应InstanceOopDesc,instanceOopDesc继承自oopDesc,用于表示普通的Java对象,每次new一个Java对象就会创建一个新的instanceOopDesc实例,其中InstanceKlass存放在元空间,InstanceOopDesc存放在堆中。
由于 Java 8 引入了 Metaspace,OpenJDK 1.8 里对象模型的实现与 1.7 有很大的不同。原先存于 PermGen 的数据都移至 Metaspace,因此它们的 C++ 类型都继承于 MetaspaceObj 类(定义见 vm/memory/allocation.hpp),表示元空间的数据。
如下一个对象组成部分所示,InstanceOopDesc是对象的头部,对象的数据部分紧跟其后。
多个对象的ModelA和ModelB的定义如下:
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);
}
如下是分配情况:
对