jvm 类加载机制

1. 虚拟机中,类型的加载,连接,初始化都是在运行期进行的,
2.类加载过程:

加载->验证->准备->解析->初始化->使用->卸载;

20140105211344671.jpg

3.初始化规则:

当遇到以下情况时必须进行先进行初始化:

1)遇到 new getStatic,putstatic,或者invokestatic这四条字节码指令时,没有初始化就应该先初始化(

这四条指令出现场景: new实例化一个对象时:读取或者设置一个类的静态字段时(被final修饰,已放入常量池的除外),调用一个静态方法时.

2)使用java.lang.reflect包的方法对类进行反射调用时.

3)初始化一个类时发现其父类未初始化,先初始化其父类

4)当虚拟机启动时,用户需要指定一个要执行的主类时(包含main方法的那个类),虚拟机会先初始化那个类

5)当使用jdk1.7的动态语言支持时,如果一个java.lang.invoke.MethodHandle实例最后的解析结果是REF_getStatic,putStatic invokeStatic,这个方法句柄对应的类没有进行过初始化,则需要先触发初始化.

当数组声明时:不会触发类的初始化而是生成一个默认类的初始化,由字节码newarray触发:

接口初始化时并不需要初始化其父类的接口.

4.类加载过程:

加载:1)通过一个类的全限定名来获取此类的二进制字节流.

   2)将这个字节流代表的静态存储结构转化为方法区的运行时数据结构

   3)在内存中生成一个代表这个类的java.lang.class对象,作为方法区这个类的各种数据的访问入口.

注意,这里第1条中的二进制字节流并不只是单纯地从Class文件中获取,比如它还可以从Jar包中获取、从网络中获取(最典型的应用便是Applet)、由其他文件生成(JSP应用)等。

数组的加载:1)如果数组的类型是n维的就递归调用加载过程,

2)如果数组的组件类型不是引用类型,例如int[] a; java虚拟机将会把数组C标记为引导类加载器关联.

3)数组类的可见性与他的组件类型的可见性一致,如果组件类型不是引用类型,数组可见性就默认public

类加载器虽然只用于实现类的加载动作,但它在Java程序中起到的作用却远远不限于类的加载阶段。对于任意一个类,都需要由它的类加载器和这个类本身一同确定其在就Java虚拟机中的唯一性,也就是说,即使两个类来源于同一个Class文件,只要加载它们的类加载器不同,那这两个类就必定不相等。这里的“相等”包括了代表类的Class对象的equals()、isAssignableFrom()、isInstance()等方法的返回结果,也包括了使用instanceof关键字对对象所属关系的判定结果。


验证:确保Class文件的字节流包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身安全

1)文件格式验证:是否以魔数0xCAFEBABE开头,等class的文件格式

2)元数据验证:对字节码描述的信息进行语义分析,保证符合规范: 这个类是否有父类,是不是抽象类等

3)字节码验证:主要目的是通过数据流和控制流的分析,确定程序语义是否合法,

4)符号引用验证:发生在虚拟机将符号引用转化为直接引用,发生在解析的过程中,:类字段的访问性(public)等


准备:是正式为类变量分配内存并设置类变量初始值得阶段,在方法区中进行分配,这里只有类变量可以,实例变量会被分配到对象实例化时的堆中: 类变量初始化设为零值.当执行类构造器时才会设置成值.

解析:是虚拟机将常量池内的符号引用替换为直接引用的过程,

符号引用:用符号来引用目标,符号可以是任何形式的字面量,与虚拟机实现的内存布局无关,

直接引用;直接指向目标的指针,相对偏移量或者一个能间接定位到目标的句柄,直接引用是和内存布局相关的,同一个符号引用在不同的虚拟机上翻译出来的直接引用一般不同,有了直接引用,那该引用的目标已经在内存中存在.


对同一个符号引用进行多次解析请求时很常见的事情,虚拟机实现可能会对第一次解析的结果进行缓存(在运行时常量池中记录直接引用,并把常量标示为已解析状态),从而避免解析动作重复进行。

 解析动作主要针对类或接口、字段、类方法、接口方法四类符号引用进行,分别对应于常量池中的CONSTANT_Class_info、CONSTANT_Fieldref_info、CONSTANT_Methodref_info、CONSTANT_InterfaceMethodref_info四种常量类型。

1、类或接口的解析:判断所要转化成的直接引用是对数组类型,还是普通的对象类型的引用,从而进行不同的解析。

 2、字段解析:对字段进行解析时,会先在本类中查找是否包含有简单名称和字段描述符都与目标相匹配的字段,如果有,则查找结束;如果没有,则会按照继承关系从上往下递归搜索该类所实现的各个接口和它们的父接口,还没有,则按照继承关系从上往下递归搜索其父类,直至查找结束,查找流程如下图所示20140105220608531.jpg

3、类方法解析:对类方法的解析与对字段解析的搜索步骤差不多,只是多了判断该方法所处的是类还是接口的步骤,而且对类方法的匹配搜索,是先搜索父类,再搜索接口。

4、接口方法解析:与类方法解析步骤类似,知识接口不会有父类,因此,只递归向上搜索父接口就行了

初始化:就是执行类构造器<clinit>的过程



参考:http://blog.csdn.net/ns_code/article/details/17881581


评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注