JVM概述
Java程序的执行过程
一个java程序,首先经过javac
编译成.class
程序, 然后JVM
将其加入到方法区,执行引擎会执行这些字节码。执行时,会翻译成操作系统的相关函数。JVM
作为.class
的翻译存在,输入字节码,调用操作系统的函数。
过程:Java文件 -> 编译器 -> 字节码 -> JVM -> 机器码
JVM 全称 Java Virtual Machine, 也就是我们耳熟能详的 Java虚拟机。它能识别.class
后缀的文件,并且能够解析它的指令,最终调用操作系统的函数,完成我们想要的操作。
字节码文件与JVM
- 我们平时所说的Java字节码,指的是Java语言编译成的字节码,准确的说任何能在JVM平台上执行的字节码格式都是一样的,所以应该统称JVM字节码
- 不同的编译器,可以编译出相同的字节码文件,字节码文件也可以在不同的JVM上运行
- Java虚拟机与Java语言并没有直接联系,它只和特定二进制文件格式 .class 文件有所关联,CLASS文件中包含JVM虚拟机指令集(bytecodes)和符号表,还有一些其它的辅助信息
JVM跨语言性的设计思路
常见的虚拟机
Hotspot虚拟机
隶属于Sun,现阶段占据 JAVA语言虚拟机市场的绝对地位,一般所提到的虚拟机都是Hotspot
虚拟机
Dalvik虚拟机 & ART虚拟机
Dalvik VM
隶属于 Google
, 应用于 Android
系统,并且在 Android2.2 中提供了 JIT
- Dalvik是一款不是JVM的JVM虚拟机,本质上它没有遵循JVM规范
- 不能直接运行java Class文件
- 它的结构是基于寄存器结构,而不是JVM栈结构
- 执行的是编译后的
Dex
文件,执行效率较高 - 与Android 5.0后被ART替换
栈指令集架构和寄存器指令集架构
Java编译器指令流是基于栈指令集架构,而另一种指令集架构为基于寄存器的指令集架构
基于栈的指令集架构的特点:
- 设计与实现简单,适用于资源受限系统
- 避开寄存器的分配问题,使用0地址指令方式
- 指令流中的指令操作过程基于栈,且位数小(8位),编译器容易实现
- 不需要硬件支撑,可移植性好
基于寄存器的指令架构特点:
x86
二进制指令集(区别于栈的8位,此处是16位):android中的Dalvik
使用的是这种架构- 依赖于硬件,可移植性差
- 性能优秀和执行更加高效
- 花费更少的时间去执行一个操作
- 基于寄存器架构的指令往往都以1~3地址指令为主,而基于栈省却地址指令操作,都基于栈完成
栈指令集:
JVM组成部分
运行时数据区
运行时数据区结构
堆栈在内存中的职责
栈是运行时的处理单位,而堆是运行时的存储单位
栈是用来解决程序运行问题,如程序如何存放,如何去处理数据,方法是怎么执行
堆是用来解决数据存储问题,数据放哪,怎么放
虚拟机栈基本信息
虚拟机栈是什么?
- 承载方法调用过程中产生的数据容器,随线程开辟,为线程私有
作用:
- 它主管java方法运行过程中所产生的值变量、运算结果、方法的调用与返回等信息管理
主核心:局部变量、计算结果
结构作用:
- 栈结构的应用能产生一种快速有效的分配方案,访问速度仅次于程序计数器
- Java直接堆栈操作只有两个:出栈、入栈
- 这种应用不需要有GC设定
程序计数器/PC寄存器
栈区存储结构与运行原理
栈内部结构解析
局部变量表
局部变量表也被称为局部变量数组或者本地变量表
定义为一个数字数组,主要用于存储方法参数和定义方法体内的局部变量
由于局部变量表是建立在线程的栈上,是线程的私有数据,因此不存在数据安全问题
局部变量表所需要的容量大小是在编译器确定下来的,并保存在方法的code属性的maxinum local variables数据项中,运行期间局部变量表大小不变
方法嵌套调用的次数由栈的大小决定,局部变量表决定着栈帧的大小,这里是编译期就会确定下来
- 默认在局部变量表第一位置入一个
this
指针 - 参数也会置入
- 内部所有声明的变量
- 注意:32位: 1slot 引用类型32位
- 大小在编译时固定