Java虚拟机栈(java stack)
虚拟机栈(java stack)
百度图片搜索里的
动图搜索功能不错,可以搜索一些动图,展示操作数栈的操作过程,比较形象。这点google差点意思
虚拟机栈(jvm stacks)是线程独占的
里面是多个栈帧(frame)或叫方法帧(class里的每个方法独占一个栈帧,所以也可以称之为方法帧)
每个栈帧里包含:局部变量区/操作数栈/动态链接/方法的返回地址
示例
文件SimpleExample.java
1 class SimpleExample {
2 public static void main(String[] args) {
3 int result = add(2,3);
4 System.out.println(result);
5 }
6 public static int add(int a, int b) {
7 return a+b;
8 }
9 }
编译源代码生产字节码文件SimpleExample.class
-g Generates all debugging information, including local variables. By default, only line number and source file information is generated.
作用是反编译的时候产生局部变量表
javac -g SimpleExample.java
反编译
javap -v -l -p SimpleExample.class
man -a javap查看帮助信息
-l Prints line and local variable tables.
-v Prints stack size, number of locals and arguments for methods.
-p Shows all classes and members.
➜ myJavaDir javap -v -l -p SimpleExample
Classfile /Users/xxxx/myJavaDir/SimpleExample.class
Last modified Oct 29, 2019; size 642 bytes
// 字节码的md5值
MD5 checksum e54540b1d2c0620b7e4eb555a8192a78
Compiled from "SimpleExample.java"
class SimpleExample
minor version: 0
major version: 52
flags: ACC_SUPER
//class常量池
Constant pool:
#1 = Methodref #6.#26 // java/lang/Object."<init>":()V
#2 = Methodref #5.#27 // SimpleExample.add:(II)I
#3 = Fieldref #28.#29 // java/lang/System.out:Ljava/io/PrintStream;
#4 = Methodref #30.#31 // java/io/PrintStream.println:(I)V
#5 = Class #32 // SimpleExample
#6 = Class #33 // java/lang/Object
#7 = Utf8 <init>
#8 = Utf8 ()V
#9 = Utf8 Code
#10 = Utf8 LineNumberTable
#11 = Utf8 LocalVariableTable
#12 = Utf8 this
#13 = Utf8 LSimpleExample;
#14 = Utf8 main
#15 = Utf8 ([Ljava/lang/String;)V
#16 = Utf8 args
#17 = Utf8 [Ljava/lang/String;
#18 = Utf8 result
#19 = Utf8 I
#20 = Utf8 add
#21 = Utf8 (II)I
#22 = Utf8 a
#23 = Utf8 b
#24 = Utf8 SourceFile
#25 = Utf8 SimpleExample.java
#26 = NameAndType #7:#8 // "<init>":()V
#27 = NameAndType #20:#21 // add:(II)I
#28 = Class #34 // java/lang/System
#29 = NameAndType #35:#36 // out:Ljava/io/PrintStream;
#30 = Class #37 // java/io/PrintStream
#31 = NameAndType #38:#39 // println:(I)V
#32 = Utf8 SimpleExample
#33 = Utf8 java/lang/Object
#34 = Utf8 java/lang/System
#35 = Utf8 out
#36 = Utf8 Ljava/io/PrintStream;
#37 = Utf8 java/io/PrintStream
#38 = Utf8 println
#39 = Utf8 (I)V
{
// 默认构造函数,即使我们不写,也会自动产生
SimpleExample();
descriptor: ()V
flags:
Code:
// 栈帧的操作数栈里有一个元素,栈帧的局部变量表里有一个变量(为this即SimpleExample对象),构造方法有一个入参(this),构建方法的第一个参数(和默认参数)是this
stack=1, locals=1, args_size=1
// 把局部变量表(数组结构)里的索引为0的数据(this对象)放入操作数栈
0: aload_0
// 调用(this)父类(这里是Object)的构造方法
1: invokespecial #1 // Method java/lang/Object."<init>":()V
// 返回,清空操作数栈和局部变量表
4: return
// 源代码和字节码指令序号的映射表
LineNumberTable:
// 代码的第一行("class SimpleExample {")对应的指令为0: aload_0
line 1: 0
// 局部变量表
LocalVariableTable:
// 变量名字是this,长度为5个字节。局部变量表第一项是个reference(引用),它指定的就是对象本身的引用,也就是我们常用的this,但是在静态方法中,没这个引用
Start Length Slot Name Signature
0 5 0 this LSimpleExample; public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
// 方法修饰符public static
flags: ACC_PUBLIC, ACC_STATIC
Code:
// 栈帧里的操作数栈为2,局部变量数量为2,参数个数为1
stack=2, locals=2, args_size=1
// 把常量池里的整数2压入操作数栈
0: iconst_2
// 把常量池里的整数3压入操作数栈
1: iconst_3
// 调用class常量池里的#2即静态方法add,返回结果入栈顶。由于该方法需要两个整数做参数,所以invokestatic从操作数栈中弹出两个元素,并将它们传给由JVM为add()创建的新栈帧,保存在add方法帧的局部变量表里。main()的操作数栈此时是空的。
2: invokestatic #2 // Method add:(II)I
// 把操作数栈的栈顶的一个整数元素取出,存入局部变量表的索引为1的位置,也就是result的值
5: istore_1
// getstatic将类型为java/io/PrintStream的静态字段java/lang/System.out压入栈中
6: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
// iload_1将局部变量表(数组结构)里的索引位置为1处的变量(就是result的值,现在等于5)压入到操作数栈中。所以此时栈保存了两个值:out字段和值5
9: iload_1
// 现在invokevirtual准备调用PrintSteam.println()方法。它从栈中弹出两个元素:第一个元素是对将要调用println()方法的对象的引用。第二个元素是一个要传递给println()方法的整型参数,它只需要一个参数。这是main()方法打印相加的结果的地方
10: invokevirtual #4 // Method java/io/PrintStream.println:(I)V
// return命令完成该方法。主帧被丢弃,JVM进程结束
13: return
LineNumberTable:
// 源代码第3行(int result = add(2,3);)对应字节码指令(0: iconst_2,1: iconst_3, 2: invokestatic #2,5: istore_1)直到(line 4: 6)
line 3: 0
line 4: 6
line 5: 13
LocalVariableTable:
// main方法栈帧的局部变量变里有两个变量args、result。静态方法,没有this引用,第一个变量就不再是this
Start Length Slot Name Signature
0 14 0 args [Ljava/lang/String;
6 8 1 result I public static int add(int, int);
// (II)I表示方法add为两个int的入参数,返回类型为int
descriptor: (II)I
flags: ACC_PUBLIC, ACC_STATIC
Code:
// 栈帧里的操作数栈为2,局部变量数量为2,参数个数为2
stack=2, locals=2, args_size=2
// 把add方法帧局部变量表里索引为0的元素值(这里为整数2)压入add方法帧的操作数栈
0: iload_0
// 把add方法帧局部变量表里索引为1的元素值(这里为整数3)压入add方法帧的操作数栈
1: iload_1
// 把操作数栈的栈顶的2个整数从操作数栈里取出,然后相加,最后把结果再次存入操作数栈
2: iadd
// 正常情况下,当前帧操作数栈的栈顶值出栈,压入调用方法的操作上栈的栈顶,丢弃当前帧操作数栈的其他值,销毁了add方法帧。恢复到调用方法帧,调用方法(invoker)继续执行
3: ireturn
LineNumberTable:
// 源代码的第7行(return a+b;)对应上面的字节码指令(0: iload_0)及后续指令
line 7: 0
LocalVariableTable:
// 栈帧里的局部变量表里有2个变量a和b,类型为int,大小都为4个字节,在局部变量表里的索引位置为0和1
Start Length Slot Name Signature
0 4 0 a I
0 4 1 b I
}
SourceFile: "SimpleExample.java"
示例:
package com.demo3;
public class Test {
public static void foo() {
int a = 1;
int b = 2;
int c = (a + b) * 5;
}
public static void main(String[] args) {
foo();
}
}
基于栈的Hotspot的执行过程如下:

参考
Java虚拟机栈(java stack)的更多相关文章
- Java虚拟机栈和PC寄存器
PC Register介绍 JVM中的程序计数寄存器(Program Counter Register)中,Register 的命名源于CPU的寄存器,寄存器存储指令相关的现场信息.CPU只有把数据装 ...
- Java虚拟机栈 和 方法区 的联系
1.Java虚拟机栈 java方法执行时的内存模型 1.1 栈帧 每个方法都会在虚拟机栈中创建一个对应的栈帧,用于存储局部变量表,操作数栈,动态链接,方法出口等信息. 一个方法的调用到结束就对应这一个 ...
- 深入理解Java虚拟机之Java内存区域与内存溢出异常
Java内存区域与内存溢出异常 运行时数据区域 程序计数器 用于记录从内存执行的下一条指令的地址,线程私有的一小块内存,也是唯一不会报出OOM异常的区域 Java虚拟机栈 Java虚拟机栈(Java ...
- JVM 运行时数据区:程序计数器、Java 虚拟机栈和本地方法栈,方法区、堆以及直接内存
Java 虚拟机可以看作一台抽象的计算机,如同真实的计算机,它也有自己的指令集和运行时内存区域. Java 虚拟机在执行 Java 程序的过程中会把它所管理的内存(运行时内存区域)划分为若干个不同的数 ...
- Java虚拟机栈---本地方法栈
1.Java虚拟机栈(Java Virtual Machine Stacks) 线程私有,它的生命周期与线程相同.描述的是Java方法执行的内存模型:每个方法在执行的同时都会创建一个栈帧(Stack ...
- JVM运行时数据区--Java虚拟机栈
虚拟机栈的背景 由于跨平台性的设计,java的指令都是根据栈来设计的.不同平台CPU架构不同,所以不能设计为基于寄存器的. 根据栈设计的优点是跨平台,指令集小,编译器容易实现,缺点是性能下降,实现同样 ...
- Java JVM——5.Java虚拟机栈
虚拟机栈概述 由于跨平台性的设计,Java 的指令都是根据栈来设计的.不同平台CPU架构不同,所以不能设计为基于寄存器的. 栈实现的优点是跨平台,指令集小,编译器容易实现,缺点是性能下降,实现同样的功 ...
- Java虚拟机栈和本地方法栈
Java虚拟机栈的特征 线程私有 后进先出(LIFO)栈 存储栈帧,支持Java方法的调用.执行和退出 可能出现OutOfMemoryError异常和StackOverflowError异常 Java ...
- java 虚拟机栈
与程序计数器一样,Java虚拟机栈也是线程私有的,他的生命周期与线程相同.虚拟机栈描述的是Java执行的内存模型:每个方法被执行的时候都会同时创建一个栈帧用于存储局部变量表,操作栈,动态链接,方法出口 ...
随机推荐
- TCP和UDP的常见面试题
问题1]为什么连接的时候是三次握手,关闭的时候却是四次握手? 答:因为当Server端收到Client端的SYN连接请求报文后,可以直接发送SYN+ACK报文.其中ACK报文是用来应答的,SYN报文是 ...
- python爬虫中涉及json数据的处理
在执行爬虫项目的过程中,有时返回的不是一个html页面而是json格式数据,此时对数据的解析非常重要. 1.Json格式数据的爬取 采用request对以上的url进行爬取: import re ...
- 项目Alpha冲刺(团队)-第九天冲刺
格式描述 课程名称:软件工程1916|W(福州大学) 作业要求:项目Alpha冲刺(团队) 团队名称:为了交项目干杯 作业目标:描述第九天冲刺的项目进展.问题困难.心得体会 队员姓名与学号 队员学号 ...
- 软帝学院教你java命名规范法则
java命名规范法则大全 在我们在刚开始学习java的时候,给包.类.方法等命名的时候总是取名不规范,大多都是随便取的,对于一个专业的程序员来说.命名规范化也是必不可少的.命名规范的话能够在编码过程中 ...
- JQuery系列(4) - AJAX方法
jQuery对象上面还定义了Ajax方法($.ajax()),用来处理Ajax操作.调用该方法后,浏览器就会向服务器发出一个HTTP请求. $.ajax方法 $.ajax()的用法主要有两种. $.a ...
- WebService(一)
最近一段时间研究webservice,一般来说,开发java的Webservice经常使用axis2和cxf这两个比较流行的框架 先使用cxf,开发一个完整示例,方便对webservice有一个整体的 ...
- 2019牛客多校第九场AThe power of Fibonacci——扩展BM
题意 求斐波那契数列m次方的前n项和,模数为 $1e9$. 分析 线性递推乘线性递推仍是线性递推,所以上BM. 由于模数非质数,上扩展版的BM. 递推多少项呢?本地输入发现最大为与前57项有关(而且好 ...
- linux 出错 “INFO: task java: xxx blocked for more than 120 seconds.” 的3种解决方案
1 问题描述 最近搭建的一个linux最小系统在运行到241秒时在控制台自动打印如下图信息,并且以后每隔120秒打印一次. 仔细阅读打印信息发现关键信息是“hung_task_timeout_secs ...
- BZOJ 4103: [Thu Summer Camp 2015]异或运算 可持久化trie
开始想了一个二分+可持久化trie验证,比正解多一个 log 仔细思考,你发现你可以直接按位枚举,然后在可持久化 trie 上二分就好了. code: #include <bits/stdc++ ...
- 安卓入门教程(十四)-菜单,ActionBar,对话框
已经发表个人公众号 菜单类型 选项菜单(OptionMenu) 子菜单(SubMenu) 上下文菜单(ContextMenu) 方法: public boolean onCreateOptionsMe ...