java 内存模型程序计数器和虚拟机栈

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/TreeShu321/article/details/101222623


java程序运行过程中会把它所管理的区域划分不同的数据区域,其中包括方法区、虚拟机栈、本地方法栈、堆、程序计数器。

一、程序计数器

程序计数器是一块 较小 的内存空间,它可以看做是当前线程所执行的字节码的 行号指示器
;在虚拟机的概念模型里(仅仅是概念模型,各种虚拟机可能会通过一些更高效的方式去实现),字节码解释器工作时,就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支、循环、跳准、异常处理、线程恢复等基础功能都需要依赖这个计数器来完成。摘自 周志明版 《深入理解java虚拟机》 P39

简单的理解就是是程序计数器保证了程序的正常执行 。

程序计数器特点
1.线程私有
2.生命周期是随线程启动而启动,线程消亡而消亡、
3.是java虚拟机规范里面, 唯一 一个 没有规定任何 OutOfMemoryError 情况的区域

程序计数器,可以看做是当前线程执行的字节码的 行号指示器 ,这句话;要理解这句话,需要先知道字节码文件长什么样子,看下面的代码


public class Hello
{
    public void say(){
        Hello he = new Hello();
        System.out.println("hello world");
    }
}

Hello类的字节码为:

public class Hello {
  public Hello();
    Code:
       0: aload_0
       1: invokespecial #1  
       4: return
 
  public void say();
    Code:
       0: new           #2      // class Hello
       3: dup
       4: invokespecial #3      // Method "<init>":()V
       7: astore_1
       8: getstatic     #4       
      11: ldc           #5      // String hello world
      13: invokevirtual #6      
      16: return
}

代码中0、3、4、7等的就是字节码指令的偏移地址,偏移地址对应的bipush 等等是jvm 中的操作指令,这是入栈指令。执行到方法say()时在当前的线程中会创建相应的程序计数器,在计数器中为存放执行地址 0 3 4…等等。
这也说明在我们程序运行过程中计数器中改变的只是值,而不会随着程序的运行需要更大的空间,也就不会发生溢出情况。

二、虚拟机栈

java虚拟机栈特点:
1、Java 虚拟机栈(Java Virtual Machine Stacks)是线程私有的,生命周期随着线程,线程启动而产生,线程结束而消亡。

2、Java 虚拟机栈描述的是 Java 方法执行的内存模型,用于存储栈帧。线程启动时会创建虚拟机栈,每个方法在执行时会在虚拟机栈中创建一个栈帧,用于存储局部变量表、操作数栈、动态连接、方法返回地址、附加信息等信息。每个方法从调用到执行完成的过程,就对应着一个栈帧在虚拟机栈中的入栈(压栈)到出栈(弹栈)的过程。

3、Java 虚拟机规范即允许 Java 虚拟机栈被实现成固定大小(-Xss),也允许通过计算结果动态来扩容和收缩大小。如果采用固定大小的 Java 虚拟机栈,那每个线程的 Java 虚拟机栈容量可以在线程创建的时候就已经确定。

Java 虚拟机栈会出现的异常
1、如果线程请求分配的栈容量超过了 Java 虚拟机栈允许的最大容量,Java 虚拟机将会抛出 StackOverflowError 异常。

2、如果 Java 虚拟机栈可以动态扩展,并且在尝试扩展的时候无法申请到足够的内存,或者在创建新的线程时没有足够的内存去创建对应的虚拟机栈,那 Java 虚拟机将抛出一个 OutOfMemoryError 异常。

Java 虚拟机栈执行过程
可参考文章:https://blog.csdn.net/azhegps/article/details/54092466

猜你喜欢

转载自blog.csdn.net/TreeShu321/article/details/101222623