JVM中的Stack和Frame

Stella981
• 阅读 531

JVM执行Java程序时需要装载各种数据,比如类型信息(Class)、类型实例(Instance)、常量数据(Constant)、本地变量等。不同的数据存放在不同的内存区中,这些数据内存区称作“运行时数据区(Runtime Data Area)”。运行时数据区有这样几个重要区:JVM Stack(简称Stack或者虚拟机栈、线程栈、栈等),Frame(又称StackFrame/栈帧、方法栈等),Heap(堆/GC堆,即垃圾收集的对象所在区)。下面简单介绍一下Stack和Frame,对于Heap,请参考垃圾收集相关文章

概览

单个线程内共享的区:PC Register/JVM Stack/Native Method Stack。
所有线程共享的区:Heap/Method Area/Runtime Constant Pool。

JVM中的Stack和Frame

上图:运行时数据区。重点是每个线程拥有的PCRegister/Stack以及线程共享的Heap以及常量池(ConstantPool)

 JVM中的Stack和Frame

上图:线程栈(VM Statck/Stack)包含的栈帧(Frame)。重点是栈帧和它的结构,操作栈(OperandStack)以及常量池引用。

Stack

结构:{JVM Stack [Frame][Frame][Frame]... }。
JVM Stack在每个线程被创建时被创建,用来存放一组栈帧(StackFrame/Frame)。
JVM Statck的大小可以是固定的,也可以是动态扩展的。如果线程需要一个比固定大小大的Stack,会发生StackOverflowError;如果动态扩展Stack时没有足够的内存或者系统没有足够的内存为新线程创建Stack,发生OutOfMemoryError。

Frame

结构:{Frame [ReturnValue] [LocalVariables[][][][]...] [OperandStack [][][]...] [ConstPoolRef] }
每次方法调用均会创建一个对应的Frame,方法执行完毕或者异常终止,Frame被销毁。一个方法A调用另一个方法B时,A的frame停止,新的frame被创建赋予B,执行完毕后,把计算结果传递给A,A继续执行。

局部变量表
局部变量表的大小在编译期就被确定。基元类型数据以及引用和返回地址(returnAddress)占用一个局部变量大小,long/double需要两个。

Java代码“int a=0;int b=1;int c=2;”对应的局部变量表如下:

LocalVariableTable: Start Length Slot Name Signature 2 12 0 a I 4 10 1 b I 6 8 2 c I

Start: 变量偏移量。
Length: 作用域范围长度。[Start,Start+Length)就是该变量的作用域。
Slot: 一个Slot能存储32bit的数据类型、引用、返回地址,long/dobule需要两个Slot。

操作栈(OperandStack)
Frame被创建时,操作栈是空的。操作栈的每个项可以存放JVM的各种类型数据,包括long/double。
操作栈有个栈深,long/double贡献两个栈深。
操作栈调用其它有返回结果的方法时,会把结果push到栈上。

Java代码:

int a=1; int b=2; int c=a+b;

对应的指令:

JVM中的Stack和Frame

0: iconst_1 // push 1到操作栈。大于5的int值会用到 bipush 指令。 1: istore_0 // pop 顶元素,存储到index=0的本地变量。 2: iconst_2 // push 2 到操作栈 3: istore_1 // pop栈顶元素,存储到index=1的本地变量。 4: iload_0 // 把index=0的本地变量加载到栈顶 5: iload_1 // 把index=1的本地变量加载到栈顶 6: iadd // 把栈顶两个数pop出来相加,并把结果存放到栈顶 7: istore_2 // 结果存储到index=2的本地变量

JVM中的Stack和Frame

Reference

1. http://blog.jamesdbloom.com/JVMInternals.html 

2. http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-2.html#jvms-2.5 

3. 《深入理解Java虚拟机》

点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Easter79 Easter79
2年前
swap空间的增减方法
(1)增大swap空间去激活swap交换区:swapoff v /dev/vg00/lvswap扩展交换lv:lvextend L 10G /dev/vg00/lvswap重新生成swap交换区:mkswap /dev/vg00/lvswap激活新生成的交换区:swapon v /dev/vg00/lvswap
Jacquelyn38 Jacquelyn38
2年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Wesley13 Wesley13
2年前
java的内存机制
Java把内存划分成两种:一种是栈内存,另一种是堆内存。 Heap(堆)Stack(栈)JVM中的功能内存数据区内存指令区存储数据对象实例基本数据类型,指令代码,常量,对象的引用地址堆中存储数据堆内存用来存放由new创建的对象和数组。 保存对象实例,实际上是保存对象实例的属性值,属性的类型和
Stella981 Stella981
2年前
JVM内存区域划分
JVM内存区域划分一、JVM运行时数据区划分根据《Java虚拟机规范》JVM会把它管理的内存划分为若干个不同的数据区域,如下图所示:方法区、堆、栈(虚拟机栈、本地方法栈)、程序计数器。线程私有的意思是指,JVM每遇到一个新的线程就会为他们分配栈和程序计数器。!(https
Stella981 Stella981
2年前
KVM调整cpu和内存
一.修改kvm虚拟机的配置1、virsheditcentos7找到“memory”和“vcpu”标签,将<namecentos7</name<uuid2220a6d1a36a4fbb8523e078b3dfe795</uuid
Wesley13 Wesley13
2年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
2年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
3个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这