`

JVM学习笔记五 之 装载(类型的生命周期系列)

    博客分类:
  • jvm
阅读更多

一、概述

      类型的生命周期分为装载、连接、初始化、实例的生命周期(使用)和卸载(实例化算是类型生命周期的一部分么?)。装载是指把表示类型信息的二进制字节码装入到内存。连接阶段包括验证、准备和解析,验证包括语法、语义、字节码流和引用验证;准备是给类变量分配内存并赋默认值;解析是把符号引用解析为直接饮用。初始化阶段是给静态变量赋值,包括静态语句和静态块里边的赋值操作。实例的生命周期阶段就包括类型实例的创建、实例的使用、实例占用内存的回收(gc)。卸载就是把类型信息占用的内存回收掉。

装载、连接和初始化三个阶段的界线在逻辑上是划分的很清晰的,但是在实际的实际过程中,除了开始时间点是跟逻辑上的先后顺序一致,具体的过程却是交叉进行的。

二、装载

      装载就是用ClassLoader把二进制字节码装载进jvm的,具体包括三个步骤:

1、根据类型的全限定名,加载二进制字节码到jvm的方法区中。此处方法区是个逻辑区域,在HotSpot VM中是非堆内存(NonHeap)的永生代(PermGen)部分。当然在别的虚拟中可能没有非堆内存这个叫法

2、把二进制静态字节码信息转化成运行期数据结构,如把静态常量池映射成运行期常量池,为字段信息、类型描述信息、超类信息、方法字节码信息等分配内存。

3、为类型信息创建java.lang.Class实例对象,该对象放在堆中,做为程序访问方法区中类型数据的外部接口。方法区中类型信息会持有一个到该java.lang.Class实例的引用,同时还会有一个到加载该类型信息的ClassLoader的一个引用。(此阶段应该在跟连接阶段交叉在一起吧,至少先验证字节码的正确性)

此处并没有要求二进制字节码是从何处得到,有了ClassLoader,开发人员可以通过很多地方获得,比如从磁盘单个class文件、目录、jar包、网络请求获得、动态生成如jsp编译成Servlet、自己拼装字节码如Proxy.getProxyClass或者通过第三方操纵字节码的类库获得如cglib。

装载阶段也是类型生命周期中java开发人员可控性最强的阶段,开发人员可以通过实现自定义的ClassLoader去控制获取二进制字节码流的方式(当然也可以自己拼装字节码),如OSGi、Tomcat都有独特的应用

三、什么时候装载一个类

jvm spec中规定在首次主动使用一个对象的时候会初始化一个类,因为初始化之前有装载和连接,所以也是触发连接的条件:

1、创建类的新实例new

2、调用类的静态方法invokestatic

3、调用类的静态非常两字段putstatic、getstatic

4、通过反射调用一个类

5、初始化一个类的子类的时候

6、jvm启动的初始化类

在被动使用一个类的时候,不会触发该类的装载。调用静态非常量字段只有当类或者接口的确声明了这个字段时才是主动调用。如超类或接口中声明了一个静态变量,但是通过子类或子接口调用的,此时对子类来说就是被动使用,不会触发子类的装载。

分享到:
评论
1 楼 javaroad 2011-10-20  
很不错。一看就知道是牛人出手。

相关推荐

Global site tag (gtag.js) - Google Analytics