乐趣区

关于java:对线面试官浅聊一下-Java-虚拟机栈

对于 JVM(Java 虚拟机)来说,它有两个十分重要的区域,一个是栈(Java 虚拟机栈),另一个是堆。堆是 JVM 的存储单位 ,所有的对象和数组都是存储在此区域的; 而栈是 JVM 的运行单位,它主管 Java 程序运行的。那么为什么它有这样的魔力?它存储的又是什么数据?接下来,咱们一起来看。

1. 栈定义

咱们先来看栈的定义,咱们这里的 栈指的是 Java 虚拟机栈(Java Virtual Machine Stack)也叫做 JVM 栈,《Java 虚拟机标准》对此区域的阐明如下:

Each Java Virtual Machine thread has a private _Java Virtual Machine stack_, created at the same time as the thread. A Java Virtual Machine stack stores frames (§2.6). A Java Virtual Machine stack is analogous to the stack of a conventional language such as C: it holds local variables and partial results, and plays a part in method invocation and return. Because the Java Virtual Machine stack is never manipulated directly except to push and pop frames, frames may be heap allocated. The memory for a Java Virtual Machine stack does not need to be contiguous.
In the First Edition of The Java® Virtual Machine Specification, the Java Virtual Machine stack was known as the Java stack.
This specification permits Java Virtual Machine stacks either to be of a fixed size or to dynamically expand and contract as required by the computation. If the Java Virtual Machine stacks are of a fixed size, the size of each Java Virtual Machine stack may be chosen independently when that stack is created.
A Java Virtual Machine implementation may provide the programmer or the user control over the initial size of Java Virtual Machine stacks, as well as, in the case of dynamically expanding or contracting Java Virtual Machine stacks, control over the maximum and minimum sizes.
The following exceptional conditions are associated with Java Virtual Machine stacks:

  • If the computation in a thread requires a larger Java Virtual Machine stack than is permitted, the Java Virtual Machine throws a StackOverflowError.
  • If Java Virtual Machine stacks can be dynamically expanded, and expansion is attempted but insufficient memory can be made available to effect the expansion, or if insufficient memory can be made available to create the initial Java Virtual Machine stack for a new thread, the Java Virtual Machine throws an OutOfMemoryError.

以上内容翻译成中文的含意如下:
Java 虚拟机栈是线程公有的区域,它随着线程的创立而创立。它外面保留的是局部变量表(根底数据类型和对象援用地址)和计算过程中的两头后果。Java 虚拟机的内存不须要间断,它只有两个操作:入栈和出栈。

Java 虚拟机栈要么大小固定,要么依据计算动静的扩大和膨胀。程序员能够对 Java 虚拟机栈进行初始值的大小设置和最大值的设置。

Java 虚拟机栈呈现的异样有两种:

  • 当 Java 虚拟机栈大小固定时,如果程序中的栈调配超过了最大虚拟机栈就会呈现 StackOverflowError 异样。
  • 如果 Java 虚拟机栈是动静扩大的,那么当内存不足时,就会引发 OutOfMemoryError 的异样。

    2. 栈构造

    栈是线程公有的,每个线程都有本人的栈(空间),栈中的数据是以栈帧(Stack Frame)的模式存在的,线程会为每个正在执行的办法生成一个栈帧,如下图所示:

    PS:当一个新的办法被调用时,就会在栈中创立一个栈帧,当办法调用实现之后,也就意味着这个栈帧会执行出栈操作。

而栈帧中又存储了 5 个内容:

  1. 局部变量表(Local Variables);
  2. 操作(数)栈(Operand Stack);
  3. 动静链接(Dynamic Linking);
  4. 办法返回地址(Return Address);
  5. 附加信息。

如下图所示:

栈的整体存储构造如下图所示:

2.1 局部变量表

局部变量表也叫做局部变量数组或本地变量表。
局部变量表是一个数组,外面存储的内容有:

  • 办法参数;
  • 办法内的局部变量,也就是办法内的根本数据类型和对象援用(Reference);
  • 办法返回类型(Return Address)。

接下来咱们通过类生成的字节码来察看一下局部变量表的内容,首先,咱们先来搞一个 main 办法,具体代码如下:

public static void main(String[] args) {
    int num = 0;
    LocalVariablesExample lv =
            new LocalVariablesExample();}

而后咱们编译类,再应用“javap -v LocalVariablesExample.class”查看字节码生成的内容,其中蕴含的本地变量表内容如下:

咱们通过 JClassLib 也能察看到局部变量表的信息,如下图所示为局部变量表的长度:

局部变量表的详细信息如下:

2.2 操作栈

操作栈也叫做操作数栈或示意式栈,操作数栈次要用于保留计算过程的两头后果,同时作为计算过程中变量长期的存储空间。

思考:为什么不把程序执行过程中的两头后果保留到局部变量表,而是保留到操作数栈中呢?

因为局部变量表是数组,而数组的长度是在其创立时就要确定,所以局部变量表在编译器就决定内容和大小了,那么在程序执行中的这些动静两头后果,是须要新的空间来保留了,而操作数栈就能够实现此性能。

2.3 动静链接

动静链接也叫做指向运行时常量池的办法援用。

这个区域的概念和作用略微难了解一点,在每一个栈帧外部都蕴含一个指向运行时常量池中该栈帧所属办法的援用。当一个办法调用了另外的其余办法时,就是通过常量池中指向办法的符号援用来示意的,那么动静链接的作用就是为了将这些符号援用转换为调用办法的间接援用。

也就是说:当一个办法调用另一个办法时,不会再创立一个被调用的办法,而是通过常量池的办法援用来调用,而这个区域存储的就是运行时常量池的办法援用,这个区域的作用就是将运行时常量池的符号援用转换成间接援用。

2.4 办法返回地址

办法返回地址也叫做办法失常退出或异样退出的定义。

办法返回地址寄存的是调用该办法的程序计数器的值。程序计数器外面保留的是该线程要执行的下一行指令的地位

也就是说:在一个办法中调用了另一个办法,当被调用的办法执行完之后,要执行的下一行指令就是保留在此区域的。

2.5 附加信息

此区域在很多教程上会被省略,因为此区域有可能有数据,也有可能没有数据。这些附加信息是和 Java 虚拟机实现相干的一些信息。例如,对程序调试提供反对的信息。

总结

栈作为 Java 虚拟机中最外围的组成部分之一,它蕴含了以下 5 局部的内容:

  1. 局部变量表(Local Variables):次要存储的是办法内的根本数据类型和对象援用;
  2. 操作(数)栈(Operand Stack):次要用于保留计算过程的两头后果,同时作为计算过程中变量长期的存储空间;
  3. 动静链接(Dynamic Linking):寄存的是指向运行时常量池的办法援用;
  4. 办法返回地址(Return Address):寄存的是调用该办法的程序计数器的值;
  5. 一些附加信息:存储了一些和 Java 虚构相干的数据,比方程序的调试数据。

参考 & 鸣谢

《阿里巴巴 Java 开发手册》
《尚硅谷 JVM》

本文已收录到 Gitee 开源仓库《Java 面试指南》,其中蕴含的内容有:Redis、JVM、并发、并发、MySQL、Spring、Spring MVC、Spring Boot、Spring Cloud、MyBatis、设计模式、音讯队列等模块。Java 面试有它就够了:超全 Java 常见面试题,继续更新 …

退出移动版