深入理解jvm 一 虚拟机类加载机制

1、类加载时机

类从被加载到虚拟机内存中开始到卸载出内存为止,整个生命周期:

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

           ------连接阶段-----

加载顺序并不是按部就班的进行,也有可能交叉式的进行。加载验证准备初始化和卸载这五个阶段的顺序是确定的。

加载

1、通过一个类的全限定名来获取此类的二进制字节流

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

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

     
验证

连接阶段第一步,确保class文件字节流包含的信息符合虚拟机的要求

验证阶段大概会完成下面四个阶段的校验动作:

1、文件格式验证:主要是class文件基本格式是否规范

2、元数据验证:对字节码描述信息进行语义分析,保证描述信息符合java语言规范

        例如这个类是否有父类、这个类的父类是否继承了fina类、如果不是抽象类是否实现了父类或接口的方法等

3、字节码验证:最复杂的一部分,确定程序语义是否合法符合逻辑。

        例如保证任意时刻操作数栈的数据类型与指令代码序列都能配合工作,保证跳转指令不会跳转到方法体以外的字节码指令上,保证方法体中类型转换是有效的。

4、符号引用验证:对类自身以外的信息进行匹配性校验(常量池中的各种符号引用),确保解析动作可以正常执行

        符号引用中通过字符串藐视的全限定名是否能找到对应的类

        在指定的类中是否存在符合方法的字段描述符以及简单名所描述的方法和字段

        符号引用中的类字段和方法的访问性是否可以被当前类访问

     
准备 z正是为类变量分配内存并设置类初始化值的阶段,变量所使用的内存都将在方法区中进行分配,这个阶段进行内存分配的仅包括static修饰的变量(类变量),数据值会被设定为0。      
解析

j解析阶段是虚拟机将常量池内的符号引用替换成直接引用的过程

        符号引用:一组符号来描述所引用的目标,一组任何形式的字面量,只要使用的时候可以无歧义的定位到目标即可。

        直接引用:直接指向目标的指针相对偏移量或间接定位到目标的句柄,如果有直接引用那么该目标一定存在内存中。


     
初始化

真正意义的执行类中定义的java程序代码

以下五种情况必须对类进行初始化:

1、遇到new、getstatic、putstatic、invokestatic这四个字节码指令,典型使用场景就是使用new创建实例化对象,读取或者设置一个静态字段以及调用一个静态方法的时候。

2、使用java.lang.reflect包的方法对类进行反射调用的时候,如果类没有被初始化则需要触发初始化。

3、当初始化一个类的时候发现他的父类还没有被初始化,则先触发父类的初始化。

4、当虚拟机启动的时候用户需要制定一个要执行的主类,包括main方法的那个类,虚拟机会先初始化这个主类。

5、当使用jdk1.7动态语言支持的时候。

初始化街二段是执行类构造器方法的过程

<clinit>()方法是由编译器自动首席类中的多有类变量的赋值动作和静态语句块中的语句合并产生的。

父类的静态语句块优先于子类的静态语句块

如果一个类没有静态语句块,也没有对变量的赋值操作,这个类可以不用产生<clinit>方法。

接口不能使用静态语句块,但是仍有变量初始化赋值操作,因此接口一样会生成<clinit>方法。


     
         

2、类加载器

每一个类加载器都拥有一个独立的类名称空间。

比较两个类是否相等,只有在这两个类是由同一个类加载器加载的前提下才有意义,否则即使两个类来源于同一个class文件,被同一个虚拟机加载,只要加载他们的类加载器不同,那么这两个类就必定不相等。

这里指的相等表示类的 equals方法 isAssignableFrom方法和isInstance方法,也包括instanceof关键字。

双亲委派模型:

只存在两种不同的类加载器:一种是启动类加载器,属于虚拟机的一部分,另一种就是所有其他的类加载器,独立于虚拟机外部,继承自java.lang.ClassLoader.

具体细分也可以分成三种:

1、启动类加载器:这个类加载器负责将存放 在<JAVA_HOME>\lib目录中的类库加载到虚拟机内存中。启动类加载器无法被java程序引用,用户在编写自定义加载器时需要把加载请求为派给引导类加载器。

2、扩展类加载器:负责加载<JAVA_HOME>\lib\ext目录中的库类,可直接使用这个类加载器

3、应用程序类加载器:这个类加载器是classloader中的getSystemClassLoader方法的返回值。他负责加载用户类路径上所指定的类库,可直接使用。一般情况下如果应用程序没有自定义过自己的类加载器,这个是默认的。

按照顺序配合加载。

所以双亲委派的模型就是要求除了顶层的启动类加载器外,其余的加载器都应当有自己的父类加载器,不是继承,而是组合。

双亲委派的模型的工作过程:如果一个类加载器接收到了类加载的请求,他首先不会自己去尝试加载这个类,而是为派给父类加载器去加载完成,每一层都是如此,因此所有的加载请求都最终传给顶层的启动类加载器中。只有父类加载器无法完成才会让子类去尝试加载。这样做的目的就是保证一些最基础的类可以被同一个加载器加载比如object类。

猜你喜欢

转载自blog.csdn.net/qq_31615049/article/details/80294279