深入理解JVM--(1)运行时的数据区域划分--java虚拟机栈

  之前我们了解了程序计数器,接下来了解第二个线程私有的数据区域--虚拟机栈。

  虚拟机栈是线程私有的,每创建一个线程,虚拟机就会为这个线程创建一个虚拟机栈,虚拟机栈表示Java方法执行的内存模型,每调用一个方法就会为每个方法生成一个栈帧(Stack Frame),用来存储局部变量表、操作数栈、动态链接、方法出口等信息。每个方法被调用和完成的过程,都对应一个栈帧从虚拟机栈上入栈和出栈的过程。个人理解虚拟机栈只为方法服务(存储变量等)

  在面试中我们经常会被问到,java内存区域划分,很多答案都是堆和栈,其中,堆细分为新生代和老年代,(永久代与方法区又与不同虚拟机的实现有关,我们会在后面进行讲解),而其中的栈指的就是虚拟机栈。或者可以认为是虚拟机栈中的局部变量表部分。

  • 局部变量表

    • 存放的是编译时期的各种基本数据类型(byte、boolean、char、short、int、float、long、double)以及对象的引用(包括指向对象地址的引用指针或者是代表对象的句柄或者是相应的位置)和returnAddress类型(指向一条字节码指令的地址:函数返回地址)
    • 局部变量表所需的内存空间在编译期间完成分配
  • 操作数栈

    • 操作数栈 遵循FIFO的原则。在操作数栈刚建立的时候为空的,只有在执行方法的时候才用于存放从局部变量表或者是全局常量等地方复制过来的数据,及生成的结果。操作数栈在存放的时候。long、double占用2个变量空间(Slot),其他占用一个。
    • 由于局部变量表的内存空间在编译期间已完成,所以在进入一个方法的时候,在操作数栈所要分配的内存空间已经完全确定,且在方法运行期间不会再发生变化
  • 动态链接方法出口

    • 每一个栈中都包含一个指向运行时常量池中的引用。常量池中存在大量的符号参数,字节码的调用就以调用常量池中指向方法的符号 引用为参数,比如在类加载或者是第一次使用的时候转化为直接引用,(final、static),还有就是在运行期间转化
    • 当一个方法通过执行后,可能会有2种情况推出,执行引擎遇到返回指令或者是遇到异常,并且异常未在方法内处理。不管哪种情况,一旦方法返回,肯定要获得返回的地址,来保证正常的执行。而且在返回时可能会保存一些信息,来完成上层的处理。正常推出时,会将程序计数器来作为返回的地址;出现异常时则会通过异常处理器来确定

  虚拟机规范还定义了在该区域的2个异常:

  • 当线程请求的栈深度大于虚拟机所允许的时候,会抛出StackOverFlowError异常
  • 当虚拟机栈动态扩容的时候,如果无法申请到足够的内存(申请的内存可能已经超过实际的内存),会抛出OutOfMemoryError异常
posted @ 2017-10-13 18:21  haoming1100  阅读(179)  评论(0编辑  收藏  举报
本文作者: haoming1100 博客链接: http://www.cnblogs.com/haoming1100 版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 3.0 许可协议。转载时必须带上原文链接!