IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 系统运维 -> 运行时数据区-虚拟机栈 -> 正文阅读

[系统运维]运行时数据区-虚拟机栈

谈谈你对虚拟机栈的理解

是什么?
Java虚拟机栈(Java Virtual Machine Stack)是线程私有的。每个线程拥有一个虚拟机栈,其内部保存一个一个的栈帧(Stack Frame),对应着一次一次的Java方法调用,即一个方法对应一个栈帧。

作用
主管Java程序的运行,它保存方法中的局部变量、部分结果,并参与方法的调用和返回。

栈的生命周期
栈的生命周期和线程一致,当线程结束了,该虚拟机栈也就销毁了。

和堆对比
栈是运行时的单位,而堆是存储的单位
栈解决程序的运行问题,即程序如何执行,如何处理数据。
堆解决的是数据存储的问题,即数据怎么放,放哪里

可能存在的异常问题
对于栈来说不存在垃圾回收问题,因为出栈即相当于回收,但是存在栈溢出的情况

Java栈的大小
分动态或固定不变两种

  • 如果大小固定
    那每一个线程的Java虚拟机栈容量可以在线程创建的时候独立选定。如果线程请求分配的栈容量超过Java虚拟机栈允许的最大容量,Java虚拟机将会抛出一个StackoverflowError 异常。

  • 如果大小动态变化
    在尝试扩展的时候无法申请到足够的内存,或者在创建新的线程时没有足够的内存去创建对应的虚拟机栈,那Java虚拟机将会抛出一个 outofMemoryError 异常。

Java的指令根据栈来设计
由于跨平台性的设计,不同平台CPU架构不同,不适合设计成基于寄存器,所以Java的指令都是根据栈来设计的。
优点是跨平台,指令集小,编译器容易实现,
缺点是性能下降,实现同样的功能需要更多的指令。

栈帧

什么是栈帧(Stack Frame)

栈帧是栈的基本存储单位,栈中的数据都是以栈帧的格式存在。一个方法对应一个栈帧。

栈帧是一个内存区块,是一个数据集,维系着方法执行过程中的各种数据信息。

不同线程的栈帧不允许相互引用
即不可能在一个线程的栈帧之中引用另外一个线程的栈帧。

当前栈帧

在一个线程中,同一时间只会有一个活动的栈帧。即只有当前正在执行的方法的栈帧是有效的
这个栈帧被称为当前栈帧(Current Frame)
与当前栈帧相对应的方法就是当前方法(Current Method)
定义这个方法的类就是当前类(Current Class)

执行引擎运行的所有字节码指令只针对当前栈帧进行操作。

如果在当前方法中调用了新的方法,对应的新的栈帧会被创建出来,放在栈的顶端,成为新的当前帧。
例如:如果当前方法A调用了其他方法B,则B成为当前方法,方法B返回之际,当前栈帧B会传回此方法的执行结果给前一个栈帧A,接着,虚拟机会丢弃当前栈帧B,使得前一个栈帧A重新成为当前栈帧
图示:
在这里插入图片描述

栈帧的内部结构

每个栈帧中包括:

  • 局部变量表(Local Variables,本地变量表)
  • 操作数栈(operand Stack,表达式栈)
  • 动态链接(DynamicLinking,指向运行时常量池的方法引用)
  • 方法返回地址(Return Address,方法正常退出或者异常退出的定义)
  • 一些附加信息

栈帧的大小主要由局部变量表 和 操作数栈 共同决定的

图示:
在这里插入图片描述
下面一一详细介绍这些内部结构

局部变量表

是什么?
主要用于存储方法参数定义在方法体内的局部变量(包括8种基本数据类型、对象引用(reference),以及return Address类型)
在方法执行时,虚拟机使用局部变量表来完成方法参数和局部变量的传递。

特点
1、由于局部变量表是栈帧的内部结构,所以是线程的私有数据,因此不存在数据安全问题

2、局部变量表的大小在编译期就确定下来了,在方法运行期间不会改变。

3、方法嵌套调用的次数由栈的大小和方法含有的数据量共同决定。
一般来说,栈越大,方法嵌套调用次数越多。
方法包含的参数和局部变量越多,栈帧就越大,嵌套调用次数越少。

4、局部变量表中的变量只在当前方法调用中有效

5、在栈帧中,与性能调优关系最为密切的部分就是局部变量表

6、局部变量表中的变量也是重要的垃圾回收根节点,只要被局部变量表中直接或间接引用的对象都不会被回收。

7、局部变量表的生命周期
和栈帧一致

Slot

什么是Slot?
Slot(变量槽)是局部变量表最基本的存储单元,一个局部变量表由N个slot组成
在局部变量表里,32位以内的类型(char,int)只占用一个slot,64位的类型(long和double)占用两个slot

栈——栈帧——局部变量表——Slot

slot的工作原理:
JVM会为局部变量表中的每一个Slot都分配一个访问索引,通过这个索引即可成功访问到局部变量表中指定的局部变量值
index=0,也就是第一个索引处放对象引用this。当一个实例方法被调用的时候,它的方法参数和方法体内部定义的局部变量将会按照顺序依次被复制到局部变量表中的每一个slot上。

Slot的重复利用
局部变量表中的slot槽位是可以重用的
举例:
下面方法localVar2中的局部变量a出了代码块,也就过了其作用域之后,就会被销毁,但是其槽位不会销毁,那么在其作用域之后申明的新的局部变量b就很有可能会复用过期局部变量a的槽位,从而达到节省资源的目的。

在这里插入图片描述

操作数栈Operand Stack

作用:
主要用于保存计算过程的中间结果,同时作为计算过程中变量临时的存储空间

工作机理:
操作数栈在方法执行过程中,根据字节码指令,往栈中写入数据或提取数据,即入栈(push)和 出栈(pop)
某些字节码指令将值压入操作数栈,其余的字节码指令将操作数取出栈。使用它们后再把结果压入栈,比如:执行复制、交换、求和等操作
在这里插入图片描述

动态链接

是什么?

  • 早期绑定–静态链接
    当一个字节码文件被装载进JVM内部时,如果被调用的目标方法编译期即可确定,且运行期保持不变时,这种情况下将调用方法的符号引用转换为直接引用过程称之为静态链接

  • 晚期绑定–动态链接
    如果被调用的方法在编译期无法被确定下来,也就是说,只能够在程序运行期将调用的方法的符号引用转换为直接引用,由于这种引用转换过程具备动态性,因此也被称之为动态链接

在这里插入图片描述

为什么需要运行时常量池?直接将方法存放在栈中不行吗?何必多此一举?———为了节约内存空间

运行时常量池中存储一份数据(张三本人),每次栈中的方法需要张三时就用“张三”指向运行时常量池来获取张三本人

否则每个栈中的方法都要存一份张三本人,太浪费空间了。

方法返回地址

一个方法的结束,有两种方式:
1、正常执行完成并退出
2、出现未处理的异常时非正常退出

无论通过哪种方式退出,在方法退出后都返回到该方法被调用的位置,即方法返回地址

一些附加信息

栈帧中还允许携带与Java虚拟机实现相关的一些附加信息。例如:对程序调试提供支持的信息。

虚方法和非虚方法

如果方法在编译期就确定了具体的调用版本,这个版本在运行时是不可变的,这样的方法称为非虚方法——静态
要等到运行期才能确定版本的为虚方法——动态

非虚方法包括:静态方法、私有方法、final方法、实例构造器、父类方法
其他方法称为虚方法

方法的调用:虚方法表

为了提高性能,JVM采用在类的方法区建立一个虚方法表
表中存放虚方法的调用版本。
非虚方法不会出现在表中,因为非虚方法在编译时就能确定其调用版本。

每个类中都有一个虚方法表,表中存放着各个方法的实际入口

虚方法表是什么时候被创建的呢?

虚方法表会在类加载的链接阶段被创建并开始初始化,类的变量初始值准备完成之后,JVM会把该类的虚方法表也初始化完毕。
在这里插入图片描述
如上图所示:如果类中重写了方法,那么调用的时候,就会直接在自己的虚方法表中去找。否则将会直接连接到Object的方法中。

面试题

调整栈大小,就能保证不出现溢出么?
不能保证不溢出。只能延长

分配的栈内存越大越好么?
不是,内存大确实可以降低OOM概率,但是会挤占其它的线程空间,因为整个空间是有限的。

垃圾回收是否涉及到虚拟机栈?
没有

方法中定义的局部变量是否线程安全?

下面举例说明是否安全(认真看)


public class StringBuilderTest {

    // s1的声明方式是线程安全的
    public static void method01() {
        // 线程内部创建的,属于局部变量
        StringBuilder s1 = new StringBuilder();
        s1.append("a");
        s1.append("b");
    }

    // 这个是线程不安全的,因为有返回值,有可能被其它的程序所调用
    public static StringBuilder method04() {
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append("a");
        stringBuilder.append("b");
        return stringBuilder;
    }

    // stringBuilder 是线程不安全的,操作的是共享数据
    public static void method02(StringBuilder stringBuilder) {
        stringBuilder.append("a");
        stringBuilder.append("b");
    }


    //同时并发的执行,会出现线程不安全的问题
    public static void method03() {
        StringBuilder stringBuilder = new StringBuilder();
        new Thread(() -> {
            stringBuilder.append("a");
            stringBuilder.append("b");
        }, "t1").start();

        method02(stringBuilder);
    }

    // StringBuilder是线程安全的,但是String也可能线程不安全的
    public static String method05() {
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append("a");
        stringBuilder.append("b");
        return stringBuilder.toString();
    }
}

总结:如果对象是在内部产生,并在内部消亡,没有返回到外部,那么它就是线程安全的,反之则是线程不安全的。

运行时数据区哪些存在Error和GC?

运行时数据区是否存在Error是否存在GC
程序计数器
虚拟机栈
本地方法栈
方法区是(OOM)

补充

栈顶缓存技术Top Of Stack Cashing

基于栈式架构的虚拟机所使用的零地址指令更加紧凑,但完成一项操作的时候必然需要使用更多的入栈和出栈指令,这同时也就意味着将需要更多的指令分派次数和内存读/写次数。由于操作数是存储在内存中的,因此更多的指令分派次数和内存读/写次数必然会影响执行速度。

为了解决这个问题,HotSpot JVM的设计者们提出了栈顶缓存技术将栈顶元素全部缓存在物理CPU的寄存器中,以此降低对内存的读/写次数,提升执行引擎的执行效率。

字节码中方法内部结构剖析

main方法:

在这里插入图片描述
可以看到下图中

Name: main

Desciptor: Ljava/lang/String 中开头的L表示引用类型变量,总共表示一维的String数组。

Access flags:访问标识(public static)

一共就完整描述了 public static void(String[] args)

在这里插入图片描述

下面就是code的介绍:
在这里插入图片描述

下面是LineNumberTable的介绍:

在这里插入图片描述
在这里插入图片描述

下面是对LocalVariableTable的描述
在这里插入图片描述

  系统运维 最新文章
配置小型公司网络WLAN基本业务(AC通过三层
如何在交付运维过程中建立风险底线意识,提
快速传输大文件,怎么通过网络传大文件给对
从游戏服务端角度分析移动同步(状态同步)
MySQL使用MyCat实现分库分表
如何用DWDM射频光纤技术实现200公里外的站点
国内顺畅下载k8s.gcr.io的镜像
自动化测试appium
ctfshow ssrf
Linux操作系统学习之实用指令(Centos7/8均
上一篇文章      下一篇文章      查看所有文章
加:2021-08-24 15:57:18  更:2021-08-24 16:02:44 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/15 11:42:43-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码