万字详解JVM,让你一文吃透( 四 )

类加载机制什么是双亲委派模型?双亲委派模型(Parents Delegation Model)要求除了顶层的启动类加载器外,其余加载器都应当有自己的父类加载器 。类加载器之间的父子关系,通过组合关系复用 。
工作过程:如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器完成 。每个层次的类加载器都是如此,因此所有的加载请求最终都应该传送到顶层的启动类加载器中,只有到父加载器反馈自己无法完成这个加载请求(它的搜索范围没有找到所需的类)时,子加载器才会尝试自己去加载 。
为什么要使用双亲委派模型,组织类加载器之间的关系?Java类随着它的类加载器一起具备了一种带优先级的层次关系 。比如java.lang.Object,它存放在rt.jar中 , 无论哪个类加载器要加载这个类,最终都是委派给启动类加载器进行加载 , 因此Object类在程序的各个类加载器环境中,都是同一个类 。
如果没有使用双亲委派模型 , 让各个类加载器自己去加载,那么Java类型体系中最基础的行为也得不到保障 , 应用程序会变得一片混乱 。

万字详解JVM,让你一文吃透

文章插图
什么是类加载机制?Class文件描述的各种信息,都需要加载到虚拟机后才能运行 。虚拟机把描述类的数据从Class文件加载到内存 , 并对数据进行校验、转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型 , 这就是虚拟机的类加载机制 。
虚拟机和物理机的区别是什么?这两种机器都有代码执行的能力,但是:
  • 物理机的执行引擎是直接建立在处理器、硬件、指令集和操作系统层面的 。
  • 虚拟机的执行引擎是自己实现的,因此可以自行制定指令集和执行引擎的结构体系,并且能够执行那些不被硬件直接支持的指令集格式 。
运行时栈帧结构栈帧是用于支持虚拟机进行方法调用和方法执行的数据结构,存储了方法的
  • 局部变量表
  • 操作数栈
  • 动态连接
  • 方法返回地址
每一个方法从调用开始到执行完成的过程,就对应着一个栈帧在虚拟机栈里面从入栈到出栈的过程 。
万字详解JVM,让你一文吃透

文章插图
Java 方法调用什么是方法调用?方法调用唯一的任务是确定被调用方法的版本(调用哪个方法),暂时还不涉及方法内部的具体运行过程 。
Java的方法调用,有什么特殊之处?Class文件的编译过程不包含传统编译的连接步骤 , 一切方法调用在Class文件里面存储的都只是符号引用 , 而不是方法在实际运行时内存布局中的入口地址 。这使得Java有强大的动态扩展能力,但使Java方法的调用过程变得相对复杂 , 需要在类加载期间甚至到运行时才能确定目标方法的直接引用 。
Java虚拟机调用字节码指令有哪些?
  • invokestatic:调用静态方法
  • invokespecial:调用实例构造器方法、私有方法和父类方法
  • invokevirtual:调用所有的虚方法
  • invokeinterface:调用接口方法
虚拟机是如何执行方法里面的字节码指令的?解释执行(通过解释器执行)编译执行(通过即时编译器产生本地代码)
解释执行当主流的虚拟机中都包含了即时编译器后 , Class文件中的代码到底会被解释执行还是编译执行,只有虚拟机自己才能准确判断 。
Javac编译器完成了程序代码经过词法分析、语法分析到抽象语法树,再遍历语法树生成线性的字节码指令流的过程 。因为这一动作是在Java虚拟机之外进行的,而解释器在虚拟机的内部,所以Java程序的编译是半独立的实现 。
基于栈的指令集和基于寄存器的指令集什么是基于栈的指令集?Java编译器输出的指令流,里面的指令大部分都是零地址指令,它们依赖操作数栈进行工作 。
计算“1+1=2”,基于栈的指令集是这样的:
iconst_1iconst_1iaddistore_0两条iconst_1指令连续地把两个常量1压入栈中,iadd指令把栈顶的两个值出栈相加,把结果放回栈顶 , 最后istore_0把栈顶的值放到局部变量表的第0个Slot中 。
什么是基于寄存器的指令集?最典型的是x86的地址指令集 , 依赖寄存器工作 。计算“1+1=2”,基于寄存器的指令集是这样的:
mov eax, 1add eax, 1mov指令把EAX寄存器的值设为1 , 然后add指令再把这个值加1,结果就保存在EAX寄存器里 。

推荐阅读