这是我参与11月更文挑战的第8天,活动详情查看:2021最后一次更文挑战
JVM
JAVA虚拟机基于栈的架构,指令由操作码和操作数组成, 字节码指令叫做opcode. JVM 靠解析opcode和操作数来完成程序的执行。
JVM翻译字节码时,有两种执行方式,常见的是解释执行, 将opcode+操作数翻译成机器代码, 另一种是JIT, 也就是即时编译。
整体架构
| 名称 | 特征 | 作用 | 参数 | 异常 |
|---|---|---|---|---|
| 程序计数器 | 占用内存小,线程私有,生命周期与线程相同 | 字节码行号指示器 | 无 | 无 |
| 虚拟机栈 | 线程私有, 生命周期与线程相同, 使用连续的内存空间 | Java方法执行的内存模型, 存储局部变量表,操作数栈, 动态链接,返回地址等 | -Xss | StackOverflowError OutOfMemoryError |
| 堆 | 线程共享, 生命周期与虚拟机相同, 可以使用不连续的内存地址 | 保存对象实例, 所有对象实例(包括数组)都要在堆上分配 | -Xms -Xsx -Xmn | OutOfMemoryError |
| 方法区 | 线程共享, 生命周期与虚拟相同, 可以使用不连续的内存地址 | 存储已被虚拟机加载的类信息,常量,静态变量, 即时编译器编译后的代码等数据 | -XX:PermSize -XX: MaxPermSize -XX: MetaspaceSize -XX: MaxMetaspaceSize | OutOfMemoryError |
| 本地方法栈 | 线程私有 | 虚拟机使用到的native方法服务 | 无 | StackOverflowError OutOfMemoryError |
JVM 分为五大模块: 类加载子系统, 运行时数据区, 执行引擎, 本地方法接口和垃圾收集器
虚拟机栈
线程私有, 存储栈帧, 每个方法执行的时候都会创建栈帧, 用于存储局部变量表,操作数栈,动态链接,方法出口。
-Xss 为JVM启动的每个线程分配的内存大小。
-Xss1m
局部变量表
变量值存储空间,存放方法参数和方法内定义的局部变量,包括8种基本数据变量,对象引用和returnAddress类型(指向下一条字节码指令的地址)。 64位长度的long和double的数据会占用2个局部变量空间(Slot), 其余占一个。
操作数栈
操作数栈也成为操作栈,是一个后入先出栈。随着方法执行和字节码指令的执行, 会从局部变量表或对象实例的字段中复制常量或变量写入操作数栈, 再随着计算的进行将栈中的元素出栈到局部变量表或者返回给方法调用者, 也就是出栈/入站操作。
动态链接
每个栈帧都包含一个指向运行时常量池中该栈所属方法的符号引用, 持有这个引用的目的是为了支持方法调用过程中的动态链接。
动态链接的作用是将符号引用转换为直接引用。
方法返回地址
存放调用该方法的PC寄存器的值。一个方法的结束, 有两种方式, 正常的执行完成, 异常非正常的退出。无论通过哪种方式退出, 在方法退出后都返回到方法被调用的位置。正常退出,调用者的PC寄存器的值作为返回地址, 异常退出,返回值通过异常表确定, 栈帧不保存这些信息。
本地方法栈
虚拟机栈是为虚拟机执行Java方法服务, 本地方法栈是为虚拟机使用的本地方法服务。