Java 是门面向对象的开发语言,那么咱们本身编写的 Java 类生成的对象是什么样的?它确定保存在虚拟机的内存中,但它以怎样的结构来保存的呢?带着疑问往下看看。数组
Java 层的开发可能不太熟悉 Klass,但确定熟悉 class,咱们只要知道 Klass 是 class 在 JVM 中的表示便可,即 Java class 对应 JVM Klass。C++ 中的继承关系以下:bash
class MetaspaceObj
class Metadata
class Klass
复制代码
Klass 类用来描述 Java 类信息,包括描述类型自身布局、类名、父类、子类、兄弟类等等。并发
按前面 class 对应的方式,那么对象也应该有 JVM 内部与之相对应的表示吧?没错,就是 oop(ordinary object pointer),普通对象指针。它的定义以下:机器学习
typedef class oopDesc* oop;
复制代码
其中 oopDesc 类是全部 oop 的基类。在 JVM 中,不一样的 oop 用于描述特定类型的对象。好比类对象用 instanceOopDesc,数组用 arrayOopDesc。分布式
Java 对象在 JVM 中的结构以下,包括 header 和对象内容。以下图中,左边的是 instanceOopDesc,即通常的类对象,header 包括了标识和元数据,标识用于存储运行时记录信息,包括哈希码、GC锁和线程锁等等。而右边的为 arrayOopDesc,即数组对象,header 多了个 length,用于记录数组长度。oop
public class Test {
private String[] flag = { "a", "b", "c" };
private String name = "test";
public static void main(String[] args) throws Exception {
Test test = new Test();
String _name = "test";
System.out.println(test.flag);
System.out.println(_name);
}
}
复制代码
在上面程序中打个断点,经过 jps 查出 pid,而后使用下面命令打开 hsdb,根据 pid 链接到 JVM。布局
jhsdb hsdb
复制代码
查看 main 线程的栈内存,咱们主要是要拿到 Test 对象的地址,即0x000000008a105dd0
。学习
接着用 inspector 来查看0x000000008a105dd0
地址对应的 oop,看到这个 oop 就是咱们的 Test 类生成的对象结构了,包含了 mark 和 metadata。这里可能会有个疑问,就是前面不是说数组还有一个 length 来表示数组长度的吗?但图中的 flag 数组变量并无看到 length 啊。ui
其实数组 oop 并非没有 length,而是 C++ 并无声明这个变量,而是经过指针来直接将数组长度保存到对应的内存了,因此这里是看不到的。经过下面具体的实现代码就能清楚了解到缘由了。是否是咱们就没办法看到这个长度值呢?并非,下面继续看如何来看这个值。this
int length() const {
return *(int*)(((intptr_t)this) + length_offset_in_bytes());
}
void set_length(int length) {
*(int*)(((intptr_t)this) + length_offset_in_bytes()) = length;
}
复制代码
前面咱们能够获得 flag 数组 oop 的地址为0x000000008a105de8
。64位机器上_mark
为8字节,_metadata
为4字节,那么将地址加12,获得0x000000008a105df4
。而后用 hsdb 命令行的 examine 获得地址的值,获得0x8a105e0800000003
,其中00000003
即是。
hsdb> examine 0x000000008a105df4
0x000000008a105df4: 0x8a105e0800000003
复制代码
-------------推荐阅读------------
跟我交流,向我提问:
公众号的菜单已分为“读书总结”、“分布式”、“机器学习”、“深度学习”、“NLP”、“Java深度”、“Java并发核心”、“JDK源码”、“Tomcat内核”等,可能有一款适合你的胃口。
欢迎关注: