在看文章之前,来举手看看有多少小伙伴是以下情况的:
表情包都说:一杯茶、一包烟,一行代码写一天。
写代码,我们是在.java文件中写的, 经过编译,会编译成.class文件,最后会通过类加载器到JVM中去。
那么请问,java类在JVM底层中如何存储的? (知道扣1、不知道扣2~~~)
那么本文就来和大家讨论一下这个问题。
Klass 模型
Java的每一个类,在JVM中,都会有一个对应的Klass类,用来存储类的元信息比如:属性信息、方法信息等等。
Klass类什么? 它是一个用C++写的一个类,看图,小编没骗你把,你也可以下载hotspot源码中查看~~
既然是一个类,那么肯定就有继承关系,先搞清楚关系,了解清楚之后,我们在来进一步验证。
这里先看这几个就好了,从父类一直看下来,最终落实到了两个类上。
InstanceKlass :如果是一个普通的Java类在JVM对应的是InstanceKlass实例。
ArrayKlass:那么如果是数组的话,那么就是用ArrayKlass来进行表示。
验证:
如果不验证,省的你们说小编瞎扯。
package com.kane.jvm;
public class Test {
public static void main(String[] args) {
while (true);
}
}
创建了一个Test类,里面启动了main线程,写了一个死循环,要保证一直处于运行的状态。
在程序运行的时候,我们使用jps命令来找对应的正在运行的虚拟机进程。(jps:JDK提供的工具,可以列出在运行的虚拟机进程,并显示出虚拟机执行的主类名称以及这些进程的本地虚拟机唯一ID)
然后我们需要通过HSDB(一个很强大的JVM运行时状态分析工具)工具来进行分析,我们只需要根据jps显示的id,找到对应进程里面的线程。
通过HSDB工具 —— File —— Attach to HotSpot process ,输入刚刚jps所打印的id
连接成功之后,点击Tools —— Class Browser,来查看当前内存中加载类的情况。
从图上可以看出,这个就是我们所运行的那个Test类,后面那0x00000000100060830就是当前Test类对应的内存地址
最后通过Tools —— Inspector ,输入Test类对应的内存地址,就可以查看对应的实例具体数据。
通过上图所示,可以看出是一个InstanceKlass类型的实例对象,也可以证明在JVM中一个普通的java类是以一个InstanceKlass类型的Klass模型存在的。
我们再来看看数组类型的,还是通过HSBD来查看,通过最后内存地址找到,可以看出类型是ArrayKlass。
package com.kane.jvm;
public class Test {
public static void main(String[] args) {
int[] arr = new int[1];
while (true);
}
}
补充说明
在jvm对应的InstanceKlass、ArrayKlass,它们也还有对应的子类,我们来看看。
InstanceMirrorKlass:是用来表示java.lang.Class,java代码中获取到的Class对象,实际上就是这个C++类的实例,存储在堆区,学名:镜像类。
InstanceRefKlass:用来表示java.lang.ref.Reference类的子类。
InstanceClassLoaderKlass:用于遍历某个加载器加载的类。
TypeArrayKlass:用来表示基本类型的数组。
ObjArrayKlass:用来表示引用类型的数组。