前置知识

阅读本文需要对以下知识有所了解:

* 栈

* 汇编

* Java 基础

* 逆波兰表达式(有学过的同学阅读本文毫无障碍)

引子

基于寄存器的设计模式

就我们所熟知的x86或arm指令集来说,其对数据的操作都是基于寄存器。例如,要对两个数执行加法操作则需要将这两个数分别送入两个寄存器再执行加法操作,这也符合我们对于编程语言认知,更加易于理解。

基于栈的设计模式

基于栈的设计模式则是将数据存放在栈中,在需要使用的时候将栈顶的数据出栈,并执行相应的操作。

举例来说,在JVM中 执行 a = b + c 的字节码执行过程中操作数栈以及局部变量表的变化如下图所示。

局部变量表中存储着a、b、c 三个局部变量,首先将b和c分别入栈

将栈顶的两个数出栈执行加法操作,并将结果保存至栈顶,之后将栈顶的数出栈赋值给a

一个简单的例子

在上一节中我们了解了栈与局部变量表是如何配合完成一次加法操作的,这一节我们将对局部变量表进行深入的研究。

如何查看局部变量表?

我们可以通过反编译class文件的方式查看局部变量表,不过在这里更加推荐使用IDEA的jclasslib插件(直接搜就有)查看字节码,因为其设计更加人性化,更加友好。

实例方法中的局部变量表

我们知道在实例方法中我们可以直接访问实例的成员变量或函数,而不需要通过this来引用,这是如何实现的?

像这种问题直接动手写个测试类,反编译一下结果自然就清晰了。

首先来一个简单的类

public class T {

    private int a = 0;

    public void add(int b,int c){
a = b + c;
}
}

其次,将该类选中,然后在view中选中showbytecode with jclasslib

效果如下:

选择我们关注的Methods中add方法,注意观察图中高亮的部分

原来,JVM在编译代码的时候,偷偷在局部变量表中添加了一个this引用(很明显this保存的实例的引用),这也是我们为什么可以在方法中访问实例中的成员变量的原因,证明如下

图中节码的简要解释如下:

0)aload_0 将this的引用入栈 (aload_0即将局部变量表中索引为0的引用压到操作数栈中)

1)iload_1 将参数b入栈 (将局部变量中的索引为1的整数压到操作数栈中)

2)iload_2 将参数c入栈

此时栈的内容有(0为栈顶)

0.c

1.b

2.this

3)iadd 将栈顶的两个数相加,并将结果保存至栈顶,此时栈的内容为

0.b+c

1.this

4). putfield 将栈顶的两个值出栈,第一个值(b+c)赋值给第二个值(this)的对应的成员变量(是的,没错即使是赋值也要执行两次出栈操作)

putfield的说明如下(注意图中的高亮部分):



地址:https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5.putfield

结论

基于栈的指令集系统可以很方便的做到平台无关性(x86、arm),但也降低了性能,这也是为啥Java性能比C低原因。(操作寄存器快,还是操作栈快?哈哈哈哈哈哈哈哈哈哈哈)

JVM 栈帧之操作数栈与局部变量表的更多相关文章

  1. 四、JVM之栈与栈帧

    栈: 1.又名堆栈,它是一种运算受限的线性表.其限制是仅允许在表的一端进行插入和删除运算.这一端被称为栈顶,相对地,把 另一端称为栈底.其特性是先进后出. 2.栈是线程私有的,生命周期跟线程相同,当创 ...

  2. 栈帧的内部结构--操作数栈(Opreand Stack)

    每个栈帧中包含: 局部变量表(Local Variables) 操作数栈(Opreand Stack) 或表达式栈 动态链接 (Dynamic Linking) (或指向运行时常量的方法引用) 动态返 ...

  3. 【死磕JVM】一道面试题引发的“栈帧”!!!

    前言 最近小农的朋友--小勇在找工作,开年来金三银四,都想跳一跳,找个踏(gao)实(xin)点的工作,这不小勇也去面试了,不得不说,现在面试,各种底层各种原理,层出不穷,小勇就遇上了这么一道面试题, ...

  4. 图解JVM字节码执行引擎之栈帧结构

    一.执行引擎      “虚拟机”的概念是相对于“物理机”而言的,这两种“机器”都有执行代码的能力.物理机的执行引擎是直接建立在硬件处理器.物理寄存器.指令集和操作系统层面的:而“虚拟机”的执行引擎是 ...

  5. JAVA栈帧

    简介 Java栈是一块线程私有的内存空间.java堆和程序数据相关,java栈就是和线程执行密切相关的,线程的执行的基本行为是函数调用,每次函数调用的数据都是通过java栈来传递的. Java栈与数据 ...

  6. Java虚拟机之栈帧

    写在前面的话:Java虚拟机是一门学问,是众多Java大神们的杰作,由于我个人水平有限,精力有限,不能保证所有的东西都是正确的,这里内容都是经过深思熟虑的,部分引用原著的内容,讲的已经很好了,不在累述 ...

  7. java 栈和栈帧

    文章转载自:http://www.tuicool.com/articles/URZrMnb jvm为每个新创建的线程都分配一个堆栈.堆栈以帧为单位保存线程的状态.jvm对堆栈只进行两种操作:以帧为单位 ...

  8. java虚拟机规范-运行时栈帧

    前言 java虚拟机是java跨平台的基石,本文的描述以jdk7.0为准,其他版本可能会有一些微调. 引用 java虚拟机规范 java虚拟机规范-运行时数据区 java内存运行时的栈帧结构 java ...

  9. 详细解析Java虚拟机的栈帧结构

    欢迎关注微信公众号:万猫学社,每周一分享Java技术干货. 什么是栈帧? 正如大家所了解的,Java虚拟机的内存区域被划分为程序计数器.虚拟机栈.本地方法栈.堆和方法区.(什么?你还不知道,赶紧去看看 ...

随机推荐

  1. WPF 入门笔记之事件

    一.事件路由 1. 直接路由事件 起源于一个元素,并且不能传递给其他元素 MouserEnter 和MouserLeave 就是直接事件路由 2. 冒泡路由事件 在包含层次中向上传递,首先由引发的元素 ...

  2. Asp.Net url参数加密存在特殊符号处理方法

    Url出现了有+,空格,/,?,%,#,&,=等特殊符号的时候,服务器端无法获得正确的参数值,解决办法. 使用System.Web.HttpUtility.UrlEncode()方法将这些字符 ...

  3. JAVA AES文件加解密

    AES加解密算法,代码如下: /** * Created by hua on 2017/6/30. */ import javax.crypto.Cipher; import javax.crypto ...

  4. HAproxy+Keepalived实现高可用

    HAproxy+Keepalived实现高可用 说明: HA1:HAproxy+Keepalived(master) HA2:HAproxy+Keepalived(backup) 1.HA1上keep ...

  5. c# Inner Join sql 和 Enumerable.Join

    using System; using System.Collections.Generic; using System.Linq; namespace ConsoleApp1 { class Pro ...

  6. java面试题库(长期)

    本文内容来自互联网各种面试实例,以及自己的面试经历,主要是中级开发的面试题 初中级java面试主要分为几个部分: 0.序 1.java基础 2. java多线程 3. jvm知识 4. spring等 ...

  7. 从后端到前端之Vue(四)小试牛刀——真实项目的应用(树、tab、数据列表和分页)

    学以致用嘛,学了这么多,在真实项目里面怎么应用呢?带着问题去学习才是最快的学习方式.还是以前的那个项目,前后端分离,现在把前端换成vue的,暂时采用脚本化的方式,然后在尝试工程化的方式. 现在先实现功 ...

  8. Linux 安装MySql——apt-get版

    0)apt-get update 1)通过apt-get安装 更新设置到最新系统:    sudo apt-get update    sudo apt-get upgrade sudo apt-ge ...

  9. Java EE.Servlet.会话管理

    一次会话是从客户打开浏览器开始到关闭浏览器结束.记录会话信息的技术称为会话跟踪.常见的会话跟踪技术有Cookie.URL重写和隐藏表单域. 1.Cookie Cookie是一小块可以嵌入到HTTP请求 ...

  10. Spring 整合 ibatis

    是的,真的是那个不好用的ibatis,不是好用的mybatis. 由于工作需要用到ibatis需要自己搭建环境,遇到了不少的坑,做一下记录. 一.环境配置 Maven JDK1.6 (非常重要,使用S ...