一、 概述
上一篇文章介绍了class文件的存储细节,class文件包括了类的各种描述信息,但是Java程序的运行需要在内存中实现,
那么虚拟机是如何加载这些class文件的?class文件中的静态结构是如何转换成实际的存储结构的?内存分配是如何完成的?这些都是本篇文章要讨论的内容。
虚拟机将类的描述文件class文件加载到内存,并且进行安全校验、数据类型解析、内存分配以及初始化,最终形成可以被虚拟机直接使用的Java类型,这个过程就是虚拟机的类加载机制。与解释执行语言不通,Java语言是编译型语言,类型的连接(即加载、连接、初始化过程)是在程序运行期进行的,这样就可以在程序运行期间动态的加载一些内容,这种形式虽然会增加系统的运行开销,但是可以让程序设计更加的灵活。
- hotspot java虚拟机Class对象是放在 方法区 还是堆中 ? Class 对象确实在堆中。
- static静态成员存放位置 static 成员保存在 Class 实例的尾部。
二、类加载的时机
一个类从加载到内存开始,一直到被卸载结束,它的整个生命周期包括加载、连接(验证、准备、解析)、初始化、使用、卸载阶段,其中连接阶段包括验证、准备和解析过程,这几个过程的发生顺序如下图所示:
什么时候触发类的加载动作呢?Java虚拟机规范并没有强制规定类加载时机,这个情况需要具体的虚拟机进行自由实现,例如Tomcat再启动时,会启动引导类加载器、拓展类加载器、通用类加载器和应用类加载器,引导类加载器、拓展类加载器和通用类加载器首先加载和初始化一些类(jvm所需类、Tomcat所需类、及一些通用类),其余的类是收到请求时才进行类的加载操作。
虽然虚拟机没有明确说明类加载的时机,但是对于初始化阶段,虚拟机规范给了严格规定,有且只有以下几种情况必须立即对类进行初始化:
- 遇到new、putstatic、getstatic及invokestatic这4条字节码指令时,如果类没有初始化,则立即进行初始化,这4个命令分别代表实例化一个类、设置&读取一个静态字段(没有被final修饰)、调用类的静态方法;
- 使用java.lang.reflect包的方法对类进行反射调用的时候,如果类没有初始化;
- 当初始化一个类的时候,发现其父类没有初始化;
- 当虚拟机启动时,需用将执行启动的主类(有main()方法的那个类)进行初始化;