一,JVM整体结构
注意点: 1,上图主要介绍JVM整体结构,从类的加载到执行引擎。 2,重点在运行时数据区(中层部分),其中方法区和堆是线程共享的,栈,本地方法栈,程序计数器是线程不共享的。 3,垃圾回收主要是在堆空间中。 4,操作系统并不能直接加载Class文件,还需经过执行引擎的加载编译,才能由操作系统识别。
二,JVM的生命周期
1,虚拟机的启动
Java虚拟机的启动是通过引导类加载器(bootstrap class loader)创建一个初始类(initial class)来完成的,这个类是由虚拟机的具体实现指定的。
2,虚拟机的执行
- 一个运行中的Java虚拟机有着一个清晰的任务:执行Java程序。
- 程序开始执行时他才运行,程序结束时他就停止
- 执行一个所谓的Java程序的时候,真真正正在执行的是一个叫做Java虚拟机的进程。
3,虚拟机的退出
有如下的几种情况:
- 程序正常执行结束
- 程序在执行过程中遇到了异常或错误而异常终止
- 由于操作系统出现错误而导致Java虚拟机进程终止
- 某线程调用Runtime类或system类的exit方法,或 Runtime类的halt方法,并且Java安全管理器也允许这次exit或halt操作。
- 除此之外,TNI ( Java Native Interface)规范描述了用JNI
Invocation API来加载或卸载 Java虚拟机时,Java虚拟机的退出情况。
三,类加载子系统
1,类的加载过程
加载:
- 1.通过一个类的全限定名获取定义此类的二进制字节流
- 2.将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构
- 3.在内存中生成一个代表这个类的java.lang.class对象,作为方法区这个类的各种数据的访问入口
链接
1,验证(Verify):
- 目的在于确保class文件的字节流中包含信息符合当前虚拟机要求,保证被加载类的正确性,不会危害虚拟机自身安全。
- 主要包括四种验证,文件格式验证,元数据验证,字节码验证,符号引用验证。
2,准备(Prepare):
- 为类变量分配内存并且设置该类变量的默认初始值,即零值。
- 这里不包含用final修饰的static,因为final在编译的时候就会分配了,准备阶段会显式初始化;
- 这里不会为实例变量分配初始化,类变量会分配在方法区中,而实例变量是会随着对象一起分配到Java堆中。
3,解析(Resolve):
- 将常量池内的符号引用转换为直接引用的过程。
- 事实上,解析操作往往会伴随着JVM在执行完初始化之后再执行。
- 符号引用就是一组符号来描述所引用的目标。符号引用的字面量形式明确定义在《java虚拟机规范》的class文件格式中。直接引用就是直接指向目标的指针、相对偏移量或一个间接定位到目标的句柄。
- 解析动作主要针对类或接口、字段、类方法、接口方法、方法类型等。对应常量池中的
CONSTANT_class_info、CONSTANT_Fieldref_info、CONSTANT_Methodref_info等。
初始化
- 初始化阶段就是执行类造器方法< clinit >()的过程。
- 此方法不需定义,是javac编译器自动收集类中的所有类变量的赋值动作和静态代码块中的语句合并而来。
- 构造器方法中指令按语句在源文件中出现的顺序执行。
- < clinit >()不同于类的构造器。(关联:构造器是虚拟机视角下的< init >() )
- 若该类具有父类,JVM会保证子类的< clinit >()执行前,父类的< clinit >()己经执行完毕。
- 虚拟机必须保证一个类的< clinit > ()方法在多线程下被同步加锁。
|