大家好,我是木野归郎,今天介绍一下JVM
先上车,后买票
类加载器与类的加载过程
类加载过程分为五部分:加载、验证、准备、解析、初始化
类加载机制
JVM把class文件加载到内存,并对数据进行校验、准备、解析、初始化,最终形成JVM可以直接使用的Java类型的过程。

下面是一个更详细的图

加载
将class字节码文件加载到内存中,并将这些数据转换成方法区中的运行时数据(静态变量、静态代码块、常量池等),在堆中生成一个Class类对象代表这个类(反射原理),作为方法区类数据的访问入口。
链接
将Java类的二进制代码合并到JVM的运行状态之中。
验证 确保加载的类信息符合JVM规范,没有安全方面的问题。
准备 正式为类变量(static变量)分配内存并设置类变量初始值的阶段,这些内存都将在方法区中进行分配。注意此时的设置初始值为默认值,具体赋值在初始化阶段完成。
解析 虚拟机常量池内的符号引用替换为直接引用(地址引用)的过程。
初始化
初始化阶段是执行类构造器初始化方法的过程。类构造器初始化方法是由编译器自动收集类中的所有类变量的赋值动作和静态语句块(static块)中的语句合并产生的。
当初始化一个类的时候,如果发现其父类还没有进行过初始化、则需要先初始化其父类。
JAVA程序初始化顺序
1、父类的静态变量 2、父类的静态代码块 3、子类的静态变量 4、子类的静态代码块 5、父类的非静态变量 6、父类的非静态代码块 7、父类的构造方法 8、子类的非静态变量 9、子类的非静态代码块 10、子类的构造方法
类加载器ClassLoader角色

1. class file存在于本地硬盘上,可以理解为设计师画在纸上的模板,而最终这个模板在执行的时候是要加载到JVM当中来根据这个文件实例化出n个一模一样的实例。
2. class file加载到JVM中,被称为DNA元数据模板,放在方法区。
3. 在.class文件->JVM->最终称为元数据模板,此过程就要一个运输工具(类装载器Class Loader),扮演一个快递员的角色。
双亲委派机制
Java虚拟机对class文件采用的是按需加载的方式,也就是说当需要使用该类时才会将它的class文件加载到内存生成class对象。而且加载某个类的class文件时,java虚拟机采用的是双亲委派模式,即把请求交由父类处理,它是一种任务委派模式。

工作原理
如果一个类加载器收到了类加载请求,它并不会自己先去加载,而是把这个请求委托给父类的加载器去执行。
如果父类加载器还存在其父类加载器,则进一步向上委托,依次递归,请求最终将达到顶层的启动类加载器。
如果父类加载器可以完成加载任务,就成功返回,倘若父类加载器无法完成此加载任务,子加载器才会尝试自己去加载,这就是双亲委派模式。
运行时数据区

不同的JVM对于内存划分方式和管理机制存在着部分差异。

Java虚拟机定义了若干种程序运行期间会使用到的运行时数据区,其中有一些会随着虚拟机启动而创建,随着虚拟机退出而销毁。另外一些则是与线程一一对应,这些与线程对应的数据区域会随着线程开始和结束而创建和销毁。

灰色的为单独线程私有的,红色的为多个线程共享的。即:
每个线程:独立包括程序计数器、栈、本地栈。
线程间共享:堆、堆外内存(永久代或元空间、代码缓存)
JVM 线程
线程是一个程序里的运行单元。JVM允许一个应用有多个线程并行执行。
在Hotspot JVM里,每个线程都与操作系统的本地线程直接映射。
当一个Java线程准备好执行后,此时一个操作系统的本地线程也同时创建。Java线程执行终止后,本地线程也会回收。
操作系统负责所有线程的安排调度到任何一个可用的CPU上。一旦本地线程初始化成功,它就会调用Java线程中的run()方法。