文档章节

栈和局部变量

javahongxi
 javahongxi
发布于 2017/08/26 06:31
字数 1538
阅读 10
收藏 0

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.  帧中存储了对应方法的局部数据,方法执行完,对应的帧则从栈中弹出,并把返回结果存储在调用 方法的帧的操作数栈中

© 著作权归作者所有

javahongxi
粉丝 168
博文 259
码字总数 779422
作品 0
朝阳
程序员
私信 提问
JVM学习之:虚拟机中的运行时栈帧总结(一)

每个人都知道,各种各样的动画视频,都是由一帧一帧图片连续切换结果的结果而产生的,其实虚拟机的运行和动画也类似,每个在虚拟机中运行的程序也是由许多的帧的切换产生的结果,只是这些帧里...

sun7545526
2012/09/20
0
0
详细介绍Java中的堆、栈和常量池

下面主要介绍JAVA中的堆、栈和常量池: 1.寄存器 最快的存储区, 由编译器根据需求进行分配,我们在程序中无法控制。 2. 栈 存放基本类型的变量数据和对象的引用,但对象本身不存放在栈中,而...

风一样
2011/08/03
21
0
深入Java核心:JVM中的栈和局部变量

Java开发中,每当我们在程序中使用new生成一个对象,对象的引用存放在栈里,而对象是存放在堆里的。可以看出栈在Java核心的重要位置。今天我们就继续深入Java核心这个系列,为您介绍Java中的...

郭二翔
2011/12/19
259
0
Java虚拟机--运行时栈帧结构

栈帧是用于支持虚拟机进行方法调用和方法执行的数据结构,它是虚拟机运行数据时数据区中的虚拟机栈的栈元素。栈帧存储了方法的局部变量表、操作数栈、动态连接和方法返回地址等信息。每个方法...

霍淇滨
2018/04/01
0
0
Java虚拟机详解02----JVM内存结构

主要内容如下: JVM启动流程 JVM基本结构 内存模型 编译和解释运行的概念 一、JVM启动流程: JVM启动时,是由java命令/javaw命令来启动的。 二、JVM基本结构: JVM基本结构图: 《深入理解J...

商者
2016/04/10
19
0

没有更多内容

加载失败,请刷新页面

加载更多

Mybatis Plus删除

/** @author beth @data 2019-10-17 00:30 */ @RunWith(SpringRunner.class) @SpringBootTest public class DeleteTest { @Autowired private UserInfoMapper userInfoMapper; /** 根据id删除......

一个yuanbeth
今天
4
0
总结

一、设计模式 简单工厂:一个简单而且比较杂的工厂,可以创建任何对象给你 复杂工厂:先创建一种基础类型的工厂接口,然后各自集成实现这个接口,但是每个工厂都是这个基础类的扩展分类,spr...

BobwithB
今天
5
0
java内存模型

前言 Java作为一种面向对象的,跨平台语言,其对象、内存等一直是比较难的知识点。而且很多概念的名称看起来又那么相似,很多人会傻傻分不清楚。比如本文我们要讨论的JVM内存结构、Java内存模...

ls_cherish
今天
4
0
友元函数强制转换

友元函数强制转换 p522

天王盖地虎626
昨天
5
0
js中实现页面跳转(返回前一页、后一页)

本文转载于:专业的前端网站➸js中实现页面跳转(返回前一页、后一页) 一:JS 重载页面,本地刷新,返回上一页 复制代码代码如下: <a href="javascript:history.go(-1)">返回上一页</a> <a h...

前端老手
昨天
5
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部