JVM源码分析之Java类的加载过程
背景
最近对Java细节的底层实现比较感兴趣,比如Java类文件是如何加载到虚拟机的,类对象和方法是以什么数据结构存在于虚拟机中?虚方法、实例方法和静态方法是如何调用的?本文基于openjdk-7的OpenJDK实现Java类在HotSpot的内部实现进行分析。
HotSpot内存划分
在HotSpot实现中,内存被划分成Java堆、方法区、Java栈、本地方法栈和PC寄存器几个部分:
1、Java栈和本地方法栈用于方法之间的调用,进栈出栈的过程;
2、Java堆用于存放对象,在Java中,所有对象的创建都在堆上申请内存,并被GC管理;
3、方法区分成PermGen和CodeCache:PermGen存放Java类的相关信息,如静态变量、成员方法和抽象方法等;CodeCache存放JIT编译之后的本地代码;
HotSpot对象模型
HotSpot JVM并没有根据Java对象直接通过虚拟机映射到新建的C++对象,而是设计了一个oop/klass model,其中oop为Ordinary Object Pointer,用来表示对象的实例信息;klass用来保存描述元数据。
从ClassLoaderCase获取一个类加载器classLoader,然后调用loadClass方法,对类进行加载
1、loadClass方法实现了双亲委派的类加载机制,如果需要自定义类加载器,建议重写内部的findClass方法,而非loadClass方法; (看以上源码,可以发现 ,调用父类loadClass方法对class类进行加载)
2、通过debug,可以发现loadClass方法最终会执行native方法defineClass1
进行类的加载,即读取对应class文件的二进制数据到虚拟机中进行解析;
class文件的解析
Java中的defineClass1方法是个native方法,说明依赖于底层的实现,在HotSpot中,其实现位于ClassLoader.c
文件中,最终调用jvm.cpp
中的jvm_define_class_common
方法实现,核心的实现逻辑如下:
把class对应的二进制文件读取到虚拟机中进行解析
1、验证全限定类名的长度,最大为(1 << 16) -1
,如果长度超过 65535,就会抛出java/lang/NoClassDefFoundError
异常,主要原因是constant pool不支持这么长的字符串;
2、SystemDictionary::resolve_from_stream
处理stream数据流,并生成Klass对象。内部通过ClassFileParser.cpp
的parseClassFile方法对class文件的数据流进行解析
1、验证当前magic