`
IXHONG
  • 浏览: 437572 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

栈和局部变量

    博客分类:
  • Java
阅读更多

Java栈概述

 

       记得当初我学习java时,常常听见身边的朋友说:“你要记住,当new一个对象时,对象的引用存放在栈里,而对象是存放在堆里的”。当时,听到这句教导时,脑海里立即出现栈的模型——里面存的仅仅是个引用。最近,看了下《深入JVM》,才发现,原来栈并不是我想象的那么简单,它和我想象中的那个栈的结构差别非常大。

     每当启用一个线程时,JVM就为他分配一个JAVA栈,栈是以帧为单位保存当前线程的运行状态。某个线程正在执行的方法称为当前方法,当前方法使用的栈帧称为当前帧,当前方法所属的类称为当前类,当前类的常量池称为当前常量池。当线程执行一个方法时,它会跟踪当前常量池。

     每当线程调用一个java方法时,JVM就会在该线程对应的栈中压入一个帧,这个帧自然就成了当前帧。当执行这个方法时,它使用这个帧来存储参数、局部变量、中间运算结果等等。

java栈上的所有数据都是私有的。任何线程都不能访问另一个线程的栈数据。所以我们不用考虑多线程情况下栈数据访问同步的情况。

像方法区和堆一样,java栈和帧在内存中也不必是连续的,帧可以分布在连续的栈里,也可以分布在堆里

 

java栈的组成元素——栈帧

 

栈帧由三部分组成:局部变量区、操作数栈、帧数据区。局部变量区和操作数栈的大小要视对应的方法而定,他们是按字长计算的。但调用一个方法时,它从类型信息中得到此方法局部变量区和操作数栈大小,并据此分配栈内存,然后压入Java栈。

 

局部变量区 局部变量区被组织为以一个字长为单位、从0开始计数的数组,类型为short、byte和char的值在存入数组前要被转换成int值,而long和double在数组中占据连续的两项,在访问局部变量中的long或double时,只需取出连续两项的第一项的索引值即可,如某个long值在局部变量区中占据的索引时3、4项,取值时,指令只需取索引为3的long值即可。

     说再多也没用,下面就看个例子,好让大家对局部变量区有更深刻的认识。这个图来着《深入JVM》:

      

Java代码  收藏代码
  1. public static int runClassMethod(int i,long l,float f,double d,Object o,byte b) {  
  2.         return 0;  
  3.     }  
  4.       
  5.     public int runInstanceMethod(char c,double d,short s,boolean b) {  
  6.         return 0;  
  7.     }  

 

    上面代码片的方法参数和局部变量在局部变量区中的存储结构如下图:

    

      

上面这个图没什么好说的,大家看看就会懂。但是,在这个图里,有一点需要注意:

 runInstanceMethod的局部变量区第一项是个reference(引用),它指定的就是对象本身的引用,也就是我们常用的this,但是在runClassMethod方法中,没这个引用,那是因为runClassMethod是个静态方法

   

    操作数栈  和局部变量区一样,操作数栈也被组织成一个以字长为单位的数组。但和前者不同的是,它不是通过索引来访问的,而是通过入栈和出栈来访问的。可把操作数栈理解为存储计算时,临时数据的存储区域。下面我们通过一段简短的程序片段外加一幅图片来了解下操作数栈的作用。

     int a = 100;

    int b = 98;

    int c = a+b;

     

 

    从图中可以得出:操作数栈其实就是个临时数据存储区域,它是通过入栈和出栈来进行操作的。

  

   

      帧数据区   除了局部变量区和操作数栈外,java栈帧还需要一些数据来支持常量池解析、正常方法返回以及异常派发机制。这些数据都保存在java栈帧的帧数据区中。

    当JVM执行到需要常量池数据的指令时,它都会通过帧数据区中指向常量池的指针来访问它。

     除了处理常量池解析外,帧里的数据还要处理java方法的正常结束和异常终止。如果是通过return正常结束,则当前栈帧从Java栈中弹出,恢复发起调用的方法的栈。如果方法又返回值,JVM会把返回值压入到发起调用方法的操作数栈

    为了处理java方法中的异常情况,帧数据区还必须保存一个对此方法异常引用表的引用。当异常抛出时,JVM给catch块中的代码。如果没发现,方法立即终止,然后JVM用帧区数据的信息恢复发起调用的方法的帧。然后再发起调用方法的上下文重新抛出同样的异常

 

   

   栈的整个结构

  

  在前面就描述过:栈是由栈帧组成,每当线程调用一个java方法时,JVM就会在该线程对应的栈中压入一个帧,而帧是由局部变量区、操作数栈和帧数据区组成。那在一个代码块中,栈到底是什么形式呢?下面是我从《深入JVM》中摘抄的一个例子,大家可以看看:

 

   代码片段:

   

  

     执行过程中的三个快照:

    

 

  上面所给的图,只想说明两件事情:

   1.  只有在调用一个方法时,才为当前栈分配一个帧,然后将该帧压入栈

   2.  帧中存储了对应方法的局部数据,方法执行完,对应的帧则从栈中弹出,并把返回结果存储在调用 方法的帧的操作数栈中

0
0
分享到:
评论

相关推荐

    成员变量和局部变量

    在类中的位置不同 成员变量:在类中方法外 局部变量:在方法内或者方法声明处 在内存中的位置不同 成员变量:在堆内存中 局部变量:在栈内存中 ... 成员变量和局部变量的名称可以一致,方法调用的时候采取就近原则

    全局变量、静态全局变量、静态局部变量和局部变量的区别2.pdf

    变量可以分为全局变量、静态全局变量、静态局部变量和局部变量 按存储区域分:全局变量、静态全局变量和静态局部变量都存放在内存的全局数据区,局部变量存放在内存的栈区 按作用域分:全局变量在整个工程文件内都...

    全局变量、局部变量、静态变量即内存管理

    全局变量,静态变量,局部变量的区别,以及其内存分配情况,栈和堆的区别

    Java字节码操作类库,基于这个api标准完成一个新的asmsupport实现

    asmsupport是一个字节码操作类库,它能够让程序员非常简单的在动态创建和修改类,该框架是基于asm开发的,不同与asm的是,它避免了直接操作jvm指令,栈和局部变量。这个模块包含了asmsupport使用的第三方依赖包的...

    深入JAVA虚拟机第二版.pdf 目录

    译者序 前言 第1章 Java体系结构介绍 ...第10章 栈和局部变量操作 第11章 类型转换 第12章 整数运算 第13章 逻辑运算 第14章 浮点运算 第15章 对象和数组 第16章 控制流 第17章 异常 第18章 finally子句

    局部变量 全局变量 堆栈总结

    堆栈(stack)是内存中的一个连续的块。一个叫堆栈指针的寄存器(SP)指向堆栈的栈顶。堆栈的底部是一个固定地址。堆栈有一个特点就是,后进先出。也就是说,后放入的数据第一个取出

    深入java虚拟机

    第10章 栈和局部变量操作 第11章 类型转换 第12章 整数运算 第13章 逻辑运算 第14章 浮点运算 第15章 对象和数组 第16章 控制流 第17章 异常 第18章 finally子句 第19章 方法的调用与返回 第20章 指令invokespecial ...

    37_全局变量和局部变量的区别1

    全局变量局部变量全局作域局部作域全局变量在静态数据区静态局部变量在静态数据区,静态局部变量在栈区存在于整个程序运期间静态局部变量存在于整个程序运期间,静态局部变

    java字节码指令集.docx

    栈和局部变量操作 将常量压入栈的指令 aconst_null 将null对象引用压入栈 iconst_m1 将int类型常量-1压入栈 iconst_0 将int类型常量0压入栈 iconst_1 将int类型常量1压入栈 iconst_2 将int类型常量2压入栈 iconst_3 ...

    深入Java虚拟机(原书第2版)及书中源代码

    第10章 栈和局部变量操作 第11章 类型转换 第12章 整数运算 第13章 逻辑运算 第14章 浮点运算 第15章 对象和数组 第16章 控制流 第17章 异常 第18章 finally子句 第19章 方法的调用与返回 第20章 指令invokespecial ...

    局部变量与全局变量区别,栈、堆和静态存储区的区别[借鉴].pdf

    局部变量与全局变量区别,栈、堆和静态存储区的区别[借鉴].pdf

    深入java虚拟机中文第2版

    第10章 栈和局部变量操作 第11章 类型转换 第12章 整数运算 第13章 逻辑运算 第14章 浮点运算 第15章 对象和数组 第16章 控制流 第17章 异常 第18章 finally子句 第19章 方法的调用与返回 第20章 指令invokespecial ...

    c++静态局部变量和静态函数示例

    在函数体内定义了一个变量,每当程序运行到该语句时都会给该局部变量分配栈内存。但随着程序退出函数体,系统就会收回栈内存,局部变量也相应失效。但有的时候我们需要在两次调用之间对变量的值进行保存。通常的想法...

    局部变量保存在栈中1

    2、对实参表从后向前,一次计算出实参的值,并且将值压栈 3、跳转到函数体处 6、将函数体中的变量、保存到栈中的实参值,依次从栈中取出,释放栈空间(出栈)

    全局变量与局部变量在内存中的区别详细解析

    1、栈区(stack)— 由编译器自动分配释放,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。 2、堆区(heap) — 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。注意它与...

    C++中 静态局部变量实例详解

    以前经常使用和了解static作用在全局变量前,以至于甚至把static当做全局变量的代名词,但是其实static还可以作用于局部变量前 静态局部变量的意义: 1.分配空间在全局数据栈上 2.作用域只局限于当前的函数范围内...

    深入java虚拟机第二版

    第10章 栈和局部变量操作 10.1 常量入栈操作 10.2 通用栈操作 10.3 把局部变量压入栈 10.4 弹出栈顶部元素,将其赋给局部变量 10.5 wide指令 10.6 一个模拟:“Fibonacci Forever” 10.7 随书光盘 10.8 资源...

    深入Java虚拟机

    第10章 栈和局部变量操作 10.1 常量入栈操作 10.2 通用栈操作 10.3 把局部变量压入栈 10.4 弹出栈顶部元素,将其赋给局部变量 10.5 wide指令 10.6 一个模拟:“Fibonacci Forever” 10.7 随书光盘 ...

    深入JAVA虚拟机(第2版)

    第10章 栈和局部变量操作 10.1 常量入栈操作 10.2 通用栈操作 10.3 把局部变量压入栈 10.4 弹出栈顶部元素,将其赋给局部变量 10.5 wide指令 10.6 一个模拟:“Fibonacci Forever” 10.7 随书光盘 ...

    xiaozhengyu#StudyNotes#8.2.1局部变量表1

    栈帧中存储的数据大致有:局部变量表、操作数栈、动态连接、方法返回地址图1 虚拟机运行时数据区域图2 栈帧的结构2. 局部变量表的说明局部变量表(Local Va

Global site tag (gtag.js) - Google Analytics