jvm通过在操作系统上简历虚拟机,自己定义出来一套统一的数据结构和操作指令,把同一套语言翻译给个大主流的操作系统,实现了跨平台运行,jvm是java的核心,是java可以一次编译到处运行的本质所在。
java 程序设计语言,java虚拟机,java API 类库这三部分统称为JDK(java development kit),jdk 是用于支持java程序开发的最小环境。java API类库中的 SE API 子集和jvm这两部分统称为JRE(java runtime environment).JRE是支持java程序运行的标准环境。
jvm的组成包括4部分:类加载,运行时数据区,执行引擎,本地库接口。
类加载
编译之后的字节码(.class)文件需要加载到虚拟机之后才能运行和使用。这里的class文件不限制于存在于具体磁盘中的文件,而是一串二进制的字节流。
虚拟机把描述类的数据从class文件加载到内存,并对数据进行校验,转换解析和初始化,最终形成可以被虚拟机直接使用的java类型,这就是虚拟机的类加载机制。
类的加载连接初始化都是在程序运行期间完成的,java的可动态扩展性就是依赖于运行期动态加载和动态连接的特点。
类从被加载到虚拟机内存中开始,到卸载出内存为止,整个生命周期包括:加载,连接(验证,准备,解析),初始化,使用和卸载。
jvm规范中严格规定了有且只有5中情况必须立即对类进行初始化:
1)遇到new,getstatic,putstatic,invokestatic这4个字节码指令时,如果类没有进行初始化,则需要先触发其初始化。
2)使用java.lang.refelect包的方法对类进行反射调用的时候,如果类没有进行过初始化,则需要先触发其初始化。
3)当初始化一个类的时候,发现其父类还没有进行过初始化,则需要先触发其父类的初始化
4)当虚拟机启动时,用户需要制定一个要执行的主类(包含main()方法的那个类),虚拟机会先初始化这个主类
5)
对于静态字段,只有直接定义这个字段的类才会被初始化,因此通过子类来引用父类中定义的静态字段,只会触发父类的初始化而不会触发子类的初始化。
类加载的过程
在加载阶段,虚拟机需要完成3件事:
1)通过类的全限定名来获取定义此类的二进制字节流
2)将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构
3)在内存中生成一个代表这个类的java.lang.class对象,作为方法区这个类的各个数据的访问入口。
由于生成了一个class的对象,可以通过反射来获取整个类的结构。
代码编译使得本地机器码转变为字节码。
所有java虚拟机的执行引擎是一致的:输入的是字节码文件,处理过程是字节码解析的等效过程,输出的是执行结果。
1:运行时栈帧结构
栈帧是支持虚拟机进行方法调用和方法执行的数据结构,是虚拟机运行时数据区中的虚拟机栈的栈元素。通常大家比较关心的栈是指虚拟机栈或者是虚拟机栈中局部变量表的部分。