《揭秘Java虚拟机》

一、概述

语言兼容的方式

  1. 编译器兼容
  2. 中间语言兼容:如Java字节码

指令

EAX 是"累加器"(accumulator), 加法乘法指令的缺省寄存器。
EBX 是"基地址"(base)寄存器, 内存寻址时存放基地址。
ECX 是计数器(counter), 是重复(REP)前缀指令和LOOP指令的内定计数器。
EDX 则总是被用来放整数除法产生的余数。
汇编指令

mov 1, %eax  //将自然数1传送给eax寄存器
pop %eax
add 3, %eax
inc %ebx
shl %eax,1  //左移一个二进位
and al,001110111B  //对al寄存器和操作数做与操作

Java字节码指令
操作数栈:虚拟栈?

  1. 数据交换指令
  2. 方法调用指令:方法代码处于类对象的Code缓存表。
  3. 运算指令
  4. 控制转移指令:循环,条件等
  5. 对象创建与类型转换指令

二 、 方法调用

方法调用=取指+运算
物理机器调用过程:

  1. 参数入栈
  2. 代码指针入栈(调用方偏移地址)
  3. 调用函数栈基地址入栈,(调用方栈基地址)
  4. 为被调用方法分配方法栈空间

JVM通过C的函数指针直接指向机器指令地址,调用机器指令

函数栈空间

  1. 栈变量区:局部变量和数据的指针
  2. 入参区域:调用其他方法传递的参数栈
  3. 寄存器保存区ip,bp:保存调用方方法代码位置和堆栈位置

函数指针

函数指针:指向函数首地址
指针函数:函数返回值为指针

CallStub函数指针

8个函数入参:
link:连接调用者和被调用者
method:方法元信息
entry_point:封装方法的工具类,类似委托模式
parameters:参数
size_of_parameters:参数数量
resul_val_address:返回值地址
result_type:返回类型
CHECK:当前线程

_cal_stub_entry

CallStub() 返回_cal_stub_entry
_cal_stub_entry生成流程:

  1. 执行pc(),获得机器码的起始位置
  2. 定义入参
  3. 保存调用者栈基
  4. 动态分配堆栈:基于元信息
  5. CallStub:调用者保存私有数据,如当前代码地址
  6. CallStub:参数压栈
  7. CallStub:调用entry_point 例程
  8. CallStub:获取返回值

三、Java数据结构与对象

平台兼容:

  1. 直接编写对应平台机器码指令
  2. 高级语言,通过编译器兼容
  3. 通过虚拟机兼容

opp-klass模型


GC时的GCRoot对象源于此。

数据类型

面向对象源于自定义数据类型。
类->特定类型的数据结构+对数据结构的操作

四、字节码文件

通过 javap -verbose [classFile]分析class文件。

  1. 魔数+版本
  2. 常量池:字面量+符号引用
  3. 字段
  4. 方法

每块通过长度标示起止,通过编译器计算得出。

五、常量池

  1. 在堆区分配内存空间:大小由编译器计算
  2. 初始化对象
  3. 初始化oop

六、类变量解析

内存对齐

char 1
short 2
int 4
通过gap填充

非静态字段分配

  1. 统计字段数量
  2. 计算偏移量(偏移地址)
  3. 计算空间

七、Java栈帧

栈帧是方法的数据栈(局部变量,上下文
环境、操作数)
堆栈是栈帧的集合
为什么是方法栈?
嵌套函数是顺序执行的,但越晚执行的函数先释放,所以用栈。

八、类方法解析

静态static{}
构造

多态

动态绑定,目的:解耦
基于vtable:指针数组,指向各method实例的首地址。

九、执行引擎

物理机执行流程:

  1. 取指
  2. 译码:何种操作(确定操作码,操作数)
  3. 执行:取操作数+运算
  4. 取下一条指令

程序计数器:指令偏移地址(esi)寄存器
译码:模板解释器(汇编器(机器码))
栈顶缓存

类的生命周期

类加载:

  1. 读取魔数和版本号
  2. 解析常量池
  3. 解析字段
  4. 解析方法
  5. 创建类的内部对象instanceKlass
  6. 创建Java镜像类

    类实例分配

    逃逸分析
    TLAB:Thread Local Allocation Buffer

Comments
Write a Comment