Java虚拟机JVM学习01 流程概述http://www.cnblogs.com/mengdd/p/3561867.html
归纳总结:自定义加载器-->应用system-->extension--->root
JAVA规范,语义,字节码,兼容性安全校验
静态变量分配内存,默认值
方法直接引用解析
堆对象,方法区
6种主动使用初始化,静态块调用跟对象初始化绑定在一起的。
目的==加载JVM,初始化对象,分配内存。虚拟机将描述类的数据从Class文件加载到内存。
GC回收,卸载自定义加载器,JDK自带不能卸载掉。
例子:类加载实例
http://computerdragon.blog.51cto.com/6235984/1223354
Java虚拟机与程序的生命周期
一个运行时的Java虚拟机(JVM)负责运行一个Java程序。
当启动一个Java程序时,一个虚拟机实例诞生;当程序关闭退出,这个虚拟机实例也就随之消亡。
如果在同一台计算机上同时运行多个Java程序,将得到多个Java虚拟机实例,每个Java程序都运行于它自己的Java虚拟机实例中。
在如下几种情况下,Java虚拟机将结束生命周期:
1.执行了System.exit()方法
2.程序正常执行结束
3.程序在执行过程中遇到了异常或错误而异常终止
4.由于操作系统出现错误而导致Java虚拟机进程终止
类加载器ClassLoader
.java文件编译生成.class文件,需要装载到内存里面执行,装载到内存里面这个事情就是由类加载器完成的。
程序执行之前,会进行类的加载、连接与初始化
1.加载
查找并加载类的二进制数据。
2.连接
连接又分为三个步骤:
验证:确保被加载类的正确性。
即验证class文件是否符合JVM的要求。
准备:为类的静态变量分配内存,并将其初始化为默认值。
解析:把类中的符号引用转换为直接引用。
参见:Java虚拟机JVM学习03 连接过程:验证、准备、解析
3.初始化
为类的静态变量赋予正确的初始值,即在程序里为静态变量指定的初始值,或静态代码块中的赋值操作。
静态代码块是从上到下顺序执行的,可以对一个静态变量多次赋值,最后的结果为静态变量的初始值。
类的加载
类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个java.lang.Class对象,用来封装类在方法区内的数据结构。
加载.class文件的方式:
1.从本地系统中直接加载
2.通过网络下载.class文件
3.从zip,jar等归档文件中加载.class文件
4.从专有数据库中提取.class文件
5.将Java源文件动态编译为.class文件
类的加载的最终产品是位于堆区中的Class对象。
Class对象封装了类在方法区内的数据结构,并且向Java程序员提供了访问方法区内的数据结构的接口。
类加载器
加载器有两种类型:
1.Java虚拟器自带的加载器
根类加载器(Bootstrap)
扩展类加载器(Extension)
系统类加载器或称应用加载器(System)
后两种加载器是Java实现的,根类加载器是C++写的,程序员无法在Java代码中获得该类。
2.用户自定义的类加载器
java.lang.ClassLoader的子类
用户可以定制类的加载方式
类加载器并不需要等到某个类被首次主动使用时再加载它。
JVM规范允许类加载器在预料某个类将要被使用时就预先加载它,如果在预先加载的过程中遇到了.class文件缺失或存在错误,类加载器必须在程序首次主动使用该类时才报告错误(LinkageError)。如果这个类一直没有被程序主动使用,那么类加载器就不会报告错误。
Java虚拟机JVM学习03 连接过程:验证、准备、解析
类被加载后,就进入连接阶段。
连接就是将已经读入到内存的类的二进制数据合并到虚拟机的运行时环境中去。
连接阶段三个步骤:验证、准备和解析。
类的验证
类的验证内容:
1.类文件的结构检查
确保类文件遵从Java类文件的固定格式。
2.语义检查
确保类本身符合Java语言的语法规定,比如验证final类型的类没有子类,以及final类型的方法没有被覆盖。
注意,语义检查的错误在编译器编译阶段就会通不过,但是如果有程序员通过非编译的手段生成了类文件,其中有可能会含有语义错误,此时的语义检查主要是防止这种没有编译而生成的class文件引入的错误。
3.字节码验证
确保字节码流可以被Java虚拟机安全地执行。
字节码流代表Java方法(包括静态方法和实例方法),它是由被称作操作码的单字节指令组成的序列,每一个操作码后都跟着一个或多个操作数。
字节码验证步骤会检查每个操作码是否合法,即是否有着合法的操作数。
4.二级制兼容性的验证
确保相互引用的类之间的协调一致。
例如,在Worker类的gotoWork()方法中会调用Car类的run()方法,Java虚拟机在验证Worker类时,会检查在方法区内是否存在Car类的run()方法,假如不存在(当Worker类和Car类的版本不兼容就会出现这种问题),就会抛出NoSuchMethodError错误。
类的准备
在准备阶段,Java虚拟机为类的静态变量分配内存,并设置默认的初始值。
例如对于以下Sample类,在准备阶段,将为int类型的静态变量a分配4个字节的内存空间,并且赋予默认值0,为long类型的静态变量b分配8个字节的内存空间,并且赋予默认值0。
package com.mengdd.classloader; public class Sample { private static int a = 1; private static long b; static { b = 2; } }
类的解析
在解析阶段,Java虚拟机会把类的二级制数据中的符号引用替换为直接引用。
例如在Worker类的gotoWork()方法中会引用Car类的run()方法。
public void gotoWork() { car.run();// 这段代码在Worker类的二进制数据中表示为符号引用 }
在Worker类的二进制数据中,包含了一个对Car类的run()方法的符号引用,它由run()方法的全名和相关描述符组成。
在解析阶段,Java虚拟机会把这个符号引用替换为一个指针,该指针指向Car类的run()方法在方法区内的内存位置,这个指针就是直接引用。