我们都知道Java是通过类加载器(classloader)将class文件加载到JVM中的。而JVM的运行时区域又可以分为:方法区、堆区、栈区、pc寄存器、本地方法栈等几个区域。那么将一个.class文件加载到JVM后,这个class到底存放在什么区域呢?
JVM规范定义了class文件的格式,也就是说class文件可以看作是对一个类型的描述,jvm加载类的步骤最终需要形成一个java.lang.Class对象的实例,我们可以通过查看classLoader的源代码得知这一点:
protected final Class> defineClass(String name, byte[] b, int off, int len,
ProtectionDomain protectionDomain)
throws ClassFormatError
{
return defineClassCond(name, b, off, len, protectionDomain, true);
}
// Private method w/ an extra argument for skipping class verification
private final Class> defineClassCond(String name,
byte[] b, int off, int len,
ProtectionDomain protectionDomain,
boolean verify)
throws ClassFormatError
{
protectionDomain = preDefineClass(name, protectionDomain);
Class c = null;
String source = defineClassSourceLocation(protectionDomain);
try {
c = defineClass1(name, b, off, len, protectionDomain, source,
verify);
} catch (ClassFormatError cfe) {
c = defineTransformedClass(name, b, off, len, protectionDomain, cfe,
source, verify);
}
postDefineClass(c, protectionDomain);
return c;
}
上面代码标红的很容易看到,在defineClass调用的方法中,创建了一个Class类的实例,最终返回的也是这个Class类的实例。
ok,我们知道Java的对象(示例)是存放在堆中的,Class类的实例一点也不例外,也是存在堆中的。至此,我们很容易的得出结论:ClassLoader加载class文件完成之后,会在方法区中存在class的描述信息(可以看作是对class结构的描述),而同时会在堆区创建这个类型的一个对象。
那么方法区中存放的这货到底包含啥呢?
摘录《深入JVM》中的一段话:
“在Java虚拟机中,关于被转载类型的信息存储在一个逻辑上叫方法区的内存中。当虚拟机装载某个类型时,它使用类装载期定位相应的class文件,然后读入这个class文件-一个线性二进制数据流,然后将他传输到虚拟机中。紧接着虚拟机提取其中的类型信息,并将这些信息存储到方法区。该类型中的类变量(静态变量)同样也是存储在方法区中。”
也就是方法区存放:1)类型信息。2)类变量(注意不是实例变量)
下个问题:类型信息是啥?