JVM运行时数据区
Java程序运行时JVM会把内存分为如下图所示的几个区域,其中包括线程所共享的堆、方法区以及线程所独有的虚拟机栈、本地方法栈和程序计数器。
一、程序计数器
程序计数器(Program Counter Register),可以看做当前线程所执行字节码行号的指示器。为了线程切换后能够恢复到之前切换前的位置,每条线程的程序计数器应该是互不干扰的。
此外若当前线程执行的是一个Java方法,此时其程序计数器中记录的是正在执行字节码指令的地址。若其是一个本地方法(c,c++方法),此时计数器值为空。
二、虚拟机栈
虚拟机栈(VMStack),该块区域也是线程私有的。虚拟机栈描述的是Java方法执行的线程模型:每个方法执行前,JVM会为该方法创建一个栈帧(Stack Frame)放入栈中,执行完毕后该栈帧出栈。
可以想象到的是当前方法(记做funA)调用另一方法(记做funB)时会为新方法产生新的栈帧存入栈顶,当funB执行完毕后将funB的栈帧出栈,然后接着执行funA方法体中剩下的代码,当funA执行完毕后,funA对应的栈帧才出栈。
对于执行引擎而言,在活动线程中只有位于栈顶的方法才是运行的,只有位于栈顶的栈帧才是生效的。该栈帧被称为当前栈帧,该方法称为当前方法。
栈帧结构如下图所示,其中包括局部变量表,操作栈等.
局部变量表
局部变量表(local variables table),其的最大空间在编译期已经确定了,方法的Code属性的max_locals指的就是局部变量表的最大空间,用于存放方法参数和方法内部定义的局部变量。如下代码中的v1、v2就是存储于局部变量表中。我们常说的”栈”内存一般指的就是局部变量表。
public class Main{
public void fun(int v1){
int v2;
}
}
局部变量表以变量槽(variable slot)为最小单位,每个变量槽都能存放一个boolean、byte、char、short、int、float、reference类型的数据,对于long类型和double类型采用分割存储的方式。
当一个方法被调用时,JVM会使用局部变量表完成实参到形参的传递;如果执行的是实力方法(非静态方法),局部变量表弟0位索引的变量槽默认传递的是对象实例的引用。
操作数栈
操作数栈(Operand Stack)又称为操作栈,其最大深度在编译期也已经确定了,max_stacks指的就是其的最大深度。32位数据类型所占栈容量为1,64位数据类型所占的栈容量为2。
当一个方法开始执行时,该方法的操作数栈为空,方法执行过程中会有各种字节码指令对操作数栈进行出栈、入栈处理。
public static void main(String[] g) {
int x = 100;
int y = 101;
int z = x + y;
}
Code:
0: bipush 100 // 将常量100加载到操作数栈
2: istore_1 // 将操作数栈顶元素存入局部变量表1号槽
3: bipush 101
5: istore_2
6: iload_1 // 将局部变量表1号槽内容加载到操作数栈
7: iload_2 // 将局部变量表2号槽内容加载到操作数栈
8: iadd // 将栈顶两数弹出并相加,并将结果重新入栈
9: istore_3
三、本地方法栈
本地方法栈(Native Method Stacks)与虚拟机栈发挥作用类似,虚拟机栈对应的是Java方法,本地方法栈对应的是本地方法。
四、堆
Java堆(Heap)是虚拟机管理的内存最大的一块,“几乎”所有对象实例都是在堆上分配的。其也是所有线程共享的一块区域,在虚拟机启动时创建。
五、方法区
方法区(Method Area)也是各个线程共享的内存区域,用于存储已经被虚拟机加载了的类信息,常量,静态变量等。《Java虚拟机规范》中对方法区的约束是非常宽松的,除了和Java堆一样不需要连续的内存和可以选择固定大小或可扩展外,甚至可以选择不实现垃圾回收。但是对该区域进行垃圾回收时必要的,主要针对常量池的回收和类的卸载。
- MVC、MVP以及Model2[下篇]
- Dora.Interception: 一个为.NET Core度身定制的AOP框架
- 为了支持AOP的编程模式,我为.NET Core写了一个轻量级的Interception框架[开源]
- 关于Expression Tree和IL Emit的所谓的"性能差别"
- 采用一个自创的"验证框架"实现对数据实体的验证[扩展篇]
- 采用一个自创的"验证框架"实现对数据实体的验证[改进篇]
- Flash XSS检测脚本的简单实现
- 采用一个自创的"验证框架"实现对数据实体的验证[设计篇]
- 采用一个自创的"验证框架"实现对数据实体的验证[编程篇]
- 谈谈你最熟悉的System.DateTime[上篇]
- 12步轻松搞定Python装饰器
- 实用小工具,教你轻松转化Python通用数据格式
- 数据工程师常用的几个小工具(附python源代码)
- R语言的三种聚类方法
- java教程
- Java快速入门
- Java 开发环境配置
- Java基本语法
- Java 对象和类
- Java 基本数据类型
- Java 变量类型
- Java 修饰符
- Java 运算符
- Java 循环结构
- Java 分支结构
- Java Number类
- Java Character类
- Java String类
- Java StringBuffer和StringBuilder类
- Java 数组
- Java 日期时间
- Java 正则表达式
- Java 方法
- Java 流(Stream)、文件(File)和IO
- Java 异常处理
- Java 继承
- Java 重写(Override)与重载(Overload)
- Java 多态
- Java 抽象类
- Java 封装
- Java 接口
- Java 包(package)
- Java 数据结构
- Java 集合框架
- Java 泛型
- Java 序列化
- Java 网络编程
- Java 发送邮件
- Java 多线程编程
- Java Applet基础
- Java 文档注释