关于虚拟机栈的理解

虚拟机栈

虚拟机栈出现的背景

由于跨平台性的设计,Java的指令都是根据栈来设计的. 不同平台CPU架构不同,所以不能设置为基于寄存器的

优点是跨平台,指令集小,编译器容易实现,缺点是性能下降,实现同样的功能需要更多的指令.


有不少Java开发人员一提到Java内存结构,就会非常粗粒度地将JVM中的内存区理解为仅有Java堆(Heap)和Java栈(stack)? 为什么

内存中的栈与堆

栈是运行时的单位,而堆是存储的单位
即: 栈解决程序的运行问题,即程序如何执行,或者说如何处理数据.
堆: 堆解决的是数据的存储的问题,即数据怎么放,放在哪儿.


比喻

java 虚拟机栈是什么?

java虚拟机栈(java virtual machine stack)早期,也叫java栈
每个线程在创建是都会创建一个虚拟机栈, 其 内部保存一个个的栈桢(stack Frame)对应着一次次的Java方法调用.

是线程私有的

声明周期

生命周期和线程一致.

作用

  • 主管java程序的运行,它保存的方法的局部变量(8种基本数据类型,对象的引用地址),部分结果,并参与方法的调用和返回.
  • 局部变量 vs 成员变量(或属性)
  • 基本数据变量 vs 引用类型变量(类,数组,接口)

实例

package com.atguigu.java5;/*** ClassName: StackTest <br/>* Description: StackTest <br/>* Date: 2020-10-23 10:36 <br/>* <br/>** @author * @version 产品版本信息 2020年10月23日10:36分 新建<br/>* <p>* 修改记录* @email * @project study_note_01* @package com.atguigu.java5*/
public class StackTest {public static void main(String[] args) {StackTest test = new StackTest();test.methodA();}public void methodA(){int i = 10;int j = 20;methodB();}public void methodB(){int k = 30;int m = 40;}
}

分析一波

栈的特点(优点)

  • 栈是一种快速有效的分配存储方式,访问速度仅此云程序计数器.
  • JVM 直接对 Java栈的操作只有两个:
    • 每个方法执行,伴随着进栈(入栈,压栈)
    • 执行结束后的出栈工作
  • 对于栈来说不存在垃圾回收问题
    • GC ; OOM ;

栈: 先入后出 子弹夹 FILO

队列: 先入先出 FIFO

面试题: 开发中遇到的异常有哪些

栈可能出现的异常

  • java 虚拟机规范允许java栈的大小是动态的或者是固定不变的
    • 如果采用固定大小的java虚拟机栈,那每一个线程的Java虚拟机栈容量可以在线程创建的时候独立选定.如果线程请求分配的栈容量超过Java虚拟机栈允许的最大容量,Java虚拟机将会抛出一个StackOverflowError异常.
    • 如果Java虚拟机可以动态扩展,并且在尝试扩展的时候无法申请到足够的内存,或者在创建新的线程时没有足够的内存区创建对应的虚拟机栈,那Java虚拟机将会抛出一个OutOfMemoryError异常

设置内存中的栈的大小

package com.atguigu.java5;/*** ClassName: StackErrorTest <br/>* Description: StackErrorTest <br/>* Date: 2020-10-23 11:01 <br/>* <br/>** @author yufengming* @version 产品版本信息 2020年10月23日11:01分 *  新建<br/>* <p>* 修改记录* @email * @project study_note_01* @package com.atguigu.java5* 默认情况下: count:11420* 设置栈的大小: -Xss 256k:*/
public class StackErrorTest {private static int count = 1;public static void main(String[] args) {System.out.println(count);count++;main(args);}
}

11410
11411
11412
Exception in thread "main" java.lang.StackOverflowErrorat sun.nio.cs.UTF_8$Encoder.encodeLoop(UTF_8.java:691)at java.nio.charset.CharsetEncoder.encode(CharsetEncoder.java:579)at sun.nio.cs.StreamEncoder.implWrite(StreamEncoder.java:271)at sun.nio.cs.StreamEncoder.write(StreamEncoder.java:125)at java.io.OutputStreamWriter.write(OutputStreamWriter.java:207)at java.io.BufferedWriter.flushBuffer(BufferedWriter.java:129)at java.io.PrintStream.write(PrintStream.java:526)at java.io.PrintStream.print(PrintStream.java:597)at java.io.PrintStream.println(PrintStream.java:736)at com.atguigu.java5.StackErrorTest.main(StackErrorTest.java:20)

栈的存储单位

栈中存储什么?

  • 每个线程都有自己的栈,栈中的数据都是以栈桢(Stack Frame)的格式存在
  • 在这个线程上正在执行的每个方法都各自对应一个栈桢(Stack Frame).
  • 栈桢是一个内存区块,是一个数据集,维系着方法执行过程中的各种数据信息.

复习

  • OOP的基本概念: 类,对象
  • 类中基本结构: field(属性,字段,域),method

栈运行原理

  • JVM 直接对Java栈的操作只有两个,就是对栈桢的压栈出栈,遵循"先进后出"/"后进先出"原则
  • 在一条活动线程中,一个时间点上,只会有一个活动的栈桢.即只有当前正在执行的方法的栈桢(栈顶栈桢)是有效的,这个栈桢被称为当前栈桢(current frame),与当前栈桢相对应的方法就是当前方法(current method),定义这个方法的类就是当前类(current class)
  • 执行引擎运行的所有字节码指令只针对当前栈桢进行操作
  • 如果在该方法中调用了其他方法,对应的新的栈桢会被创建出来,放在栈的顶端,成为新的当前帧.

当前栈桢,一直在移动

依次执行

  • 不同线程中所包含的栈桢是不允许存在相互引用的,即不可能在一个栈桢之中引用另外一个线程的栈桢.
  • 如果当前方法调用了其他方法,方法返回之际,当前栈桢会传回此方法的执行结果给前一个栈桢,接着,虚拟机会丢弃当前栈桢,使得前一个栈桢重新成为当前栈桢.
  • Java方法有两种返回函数的方式,一种是正常的函数返回,使用return指令;另外一种是抛出异常.不管使用哪种方式,都会导致栈桢被弹出.

栈桢内部结构

在虚拟机这块儿,有错误的帖子很多,你不能全信

垃圾回收算法

局部变量表

  • 局部变量表也被称之为局部变量数组或本地变量表
  • **定义为一个数字数组,主要用于存储方法参数和定义在方法体内的局部变量,**这些数据类型包括各类基本数据类型,对象引用(reference),以及returnAddress类型.
  • 由于局部变量表示建立在线程的栈上,是线程的私有数据,因此不存在数据安全问题
  • 局部变量表所需的容量大小是在编译期确定下来的,并保存在方法Code属性的maximum local variables 数据项中.在方法运行期间是不会改变局部变量表的大小的.

javap 命令 解析,这个idea具有反编译功能

idea中jclasslib 插件

  • 方法嵌套调用的次数由栈的大小决定.一般来说,**栈越大,方法嵌套调用次数越多.**对一个函数而言,它的参数和局部变量越多,使得局部变量表膨胀,它的栈桢就越大,以满足方法调用所需传递的信息增大的需求.进而函数调用就会占用更多的栈空间,导致其嵌套调用次数就会减少.
  • **局部变量表中的
  • **.在方法执行时,虚拟机通过使用局部变量表完成参数值到参数变量列表的传递过程.**当方法调用结束后,随着方法栈桢的销毁,局部变量表也会随之销毁.

关于Slot的理解

  • 参数值的存放总是在局部变量数组index0 开始,到数组长度-1 的索引结束.

  • 局部变量表,最基本的存储单元是Slot(变量槽)

  • 局部变量表中存放编译期可知的各种基本数据类型(8种),引用类型(reference),returnAddress类型的变量.

  • 在局部变量表里,32位以内的类型只占用一个slot(包括returnAddress类型),64位的类型(long和double)占用两个slot.

  • byte,short,char 在存储前被转换为int,boolean也被转换为int,0 表示 false,非0 表示 true.

  • long和double 则占据两个Slot.

  • JVM会为局部变量表中的每一个Slot都分配一个访问索引,通过这个索引即可成功访问到局部变量表中指定的局部变量值

  • 当一个实例方法被调用的时候,它的方法参数和方法体内部定义的局部变量将会按照顺序被复制到局部变量表中的每一个Slot上

  • 如果需要访问局部变量表中一个64bit的局部变量值时,只需要使用前一个索引即可.(比如: 访问long或double类型变量)

  • 如果当前帧是由构造方法或者实例方法创建的,name该对象引用this将会存放在index为0的slot处,其余的参数按照参数表顺序继续排列

4分钟

构造器中的this,表示当前创建的变量


栈桢中的布局变量表中的槽位是可以重用的,如果一个局部变量过了其作用域,那么在其作用域之后申明的新的局部变量就会很有可能会复用过期局部变量的槽位,从而达到节省资源的目的

变量的分类

按照数据类型:

  1. 基本数据类型
  2. 引用数据类型

按照在类中声明的位置:

  1. 成员变量: 在使用前都经历过初始化赋值
  • 使用静态来修饰的(类变量):
    • linking的prepare阶段:给类变量默认赋值 —>
    • initial阶段: 给类变量显示赋值即静态代码
  • 实例变量(归具体的对象所有)
    :随着对象的创建,会在堆空间中分配实例变量空间,并进行默认赋值
  1. 局部变量: 在使用前,比如要进行显示赋值,否则,编译不通过
public void test5Temp(){int num;System.out.println(num);// 错误信息,变量num没有进行赋值(未初始化错误)
}

补充说明

  • 在栈桢当中,与性能调优关系最为密切的部分就是前面提到的局部变量表.
    在方法的执行时,虚拟机使用局部变量表完成方法的传递.
  • 局部变量表中的变量也是重要的垃圾回收根节点,只要被局部变量表中直接或间接引用的对象都不会被回收.

在静态的方法当中是不可以引用这个this的

Slot的重复利用

栈桢当中的局部变量表中的槽位是可以重用的,如果一个局部变量过了其作用域,那么在其他作用域之后申明的新的局部变量就很哟与可能会复用过期局部变量的槽位,从而达到节省资源的目的

52 操作数栈(Operate Stack)

这个是数据结构中的一种,先进后出的特点

栈: 可以通过数组或链表来实现
栈可以看成满足特殊条件的数组或者链表.


  • 每一个独立的栈桢当中除了包含局部变量表以外,还包含一个后进献出(Last-In-First-Out)的操作数栈,也可以称之为表达式栈(Expression Stack)

  • 操作数栈,在方法执行过程中,根据字节码指令,往栈中写入数据或提取数据,即入栈(push)/出栈(pop).

    • 某些字节码指令将值亚入操作数栈,其余的字节码指令将操作数取出栈.使用它们后再把结果压入栈.
    • 比如:执行复制交换,求和等操作.
  • 操组数栈,主要用于保存计算过程的中间计算结果,同时作为计算过程中变量临时的存储空间

  • 操作数栈就是JVM执行引擎的一个工作区,当一个方法刚开始执行的时候,一个新的栈桢也会随之被创建出来,这个方法的操作数栈是空的

  • 每一个操作数栈都会拥有一个明确的栈深度用于存储数值,其所需的最大深度在编译期就定义好了,保存在方法的Code属性中,为Max_stack的值.

  • 栈中的任何一个元素都是可以任意Java数据类型

    • 32bit的类型占用一个栈单位深度
    • 64bit的类型占用两个栈单位深度
  • 操作数栈并非采用访问索引的方式来进行数据访问的,而是只能通过标准的入栈(push)和出栈(pop)操作来完成一次数据访问.

  • 如果被调用的方法带有返回值的话,其返回值将会被压入当期栈桢的操作数栈中,并更新PC寄存器中吓一跳需要执行的字节码指令.

  • 操组数栈中元素的数据类型比如与字节码执行的序列严格匹配,这由编译器在编译期间进行验证,同时在类加载过程中的类检验阶段的数据流分析阶段要再次验证.

  • 另外,我们说Java虚拟机的解释引擎是基于栈的执行引擎,其中的栈值的就是操作数栈.

动态链接(或指向运行时常量池的方法引用)

动态链接


方法的调用

在java虚拟机当中,将符号引用转换为调用方法的直接引用于方法的绑定机制相关

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

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

方法的调用

对应的方法的绑定机制为: 早期绑定(Early Binding) 和晚期绑定(Late Binding). **绑定是一个字段,方法或者类在符号引用被替换为直接引用的过程,这仅仅发生一次.

  • 早期绑定:
    早期绑定就是指被调用的目标方法如果在编译期可知,且运行期保持不变时,即可将这个方法与所属的类型进行绑定,这样一来,由于明确了被调用的目标方法究竟是哪一个,因此也就可以使用静态链接的方式将符号引用转换为直接引用.
  • 晚期绑定:
    如果被调用的方法在编译期无法被确定下来,只能够在程序运行期根据实际的类型绑定相关的方法,这种绑定方式也就被称之为晚期绑定
    随着高级语言的横空出世,类似于Java一样的基于面向对象的编程语言如今越来越多,尽管这类编程语言在语法风格上存在一定的差别,但是它们彼此之间始终保持着一个共性,那就是都支持封装\继承,和多态等面向对象特性,既然这一类的编程语言具备多态特性,那么自然也就具备早期绑定和晚期绑定两种绑定方式.

Java 中任何一个普通的方法其实都具备虚函数的特征,它们相当于C++语言中的虚函数(C++中则需要使用关键字Virtual来进行显示的定义).如果在Java程序汇总不希望某个方法拥有虚函数的特征时,则可以使用关键字final来标记这个方法.

虚方法和非虚方法

非虚方法

  • 如果方法在编译期就确定了具体的调用版本,这个版本在运行时是不可变的.这样的方法称为非虚方法
  • 静态方法,私有方法,final方法,实例构造器,父类方法都是非虚方法.
  • 其他方法称为虚方法.

多态的使用前提:
1 类的继承关系
2 方法的重写

虚拟机中提供了一些几条方法调用指令:

  • 普通调用指令:
    1. invokestatic: 调用静态方法,解析阶段确定唯一方法版本
    2. invokespecial: 调用方法,私有及父类方法,解析阶段确定唯一方法版本
    3. invokevirtual: 调用所有虚方法
    4. invokeinterface: 调用接口方法
  • 动态调用指令:
    5. invokedynamic: 动态解析出需要调用的方法,然后执行

前4条指令固化在虚拟机内部,方法的调用执行不可人为干预,而invokedynamic指令则支持由用户确定方法版本.其中invokestatic指令和invokespecial指令调用的方法称为非虚方法,其余的(final修饰的除外)称为虚方法.

练习一下

package com.atguigu.java6;/**\*解析*/
class Father{public Father() {System.out.println("father的构造器~");}public static void showStatic(String str) {System.out.println("Father"+str);}public final void showFinal() {System.out.println("father show final!");}public void showCommon() {System.out.println("father 普通方法!");}}
public class Son extends Father{public Son() {super();}public Son(int age) {this();}/*** 不是重写的父类方法* @param str*/public static void showStatic(String str) {System.out.println(str);}private void showPrivate(String str) {System.out.println("son private"+str);}public void show() {showStatic("autaied.com");super.showStatic("ggoaset");showPrivate("hellow!");super.showCommon();showFinal();showCommon();info();//        MethodInterface in = null;
//        in.methodA();}public void info() {}public static void main(String[] args) {new Son().show();}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/455154.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

抓取各个浏览器引擎关键字,,百度学术关键字

百度学术 $list_arr getbaiduxueshu($row[name]); $list_arr explode((,$list_arr); $list_arr explode(),$list_arr[1]); $list_arr json_decode($list_arr[0]); $list_arr $list_arr->s; //百度学术平台热词地址function getbaiduxueshu($keyname 100){ $url http:…

wave格式分析,wave音频文件格式分析配程序

wav文件格式分析详解 程序如上一篇博文 一、综述 WAVE文件作为多媒体中使用的声波文件格式之一&#xff0c;它是以RIFF格式为标准的。RIFF是英文Resource Interchange File Format的缩写&#xff0c;每个WAVE文件的头四个字节便是“RIFF”。 WAVE文件是由若干个Chunk组成…

poi设置word表格单元格宽度_java poi如何设置word的页面的大小和水平方向?

展开全部你好&#xff0c;试试以下代码行不行。packagecom.sample;importjava.awt.color;importjava.io.fileoutputstream;importjava.io.ioexception;importcom.lowagie.text.cell;importcom.lowagie.text.document;importcom.lowagie.text.documentexception;importcom.lowag…

时间通用方法

import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date;import org.apache.commons.lang3.time.DateFormatUtils;/** * 日期工具类, 继承org.apache.commons.lang.time.DateUtils类 */ public class DateUtils extends org.apache.commo…

Python-MongoDB的驱动安装、升级

安装pip&#xff0c;并通过此来安装pymongo–Python mongodb驱动 1、下载pip安装包&#xff0c;下载地址&#xff1a;http://pypi.python.org/packages/source/p/pip/pip-1.0.2.tar.gz#md547ec6ff3f6d962696fe08d4c8264ad49 2、解压安装&#xff1a; tar -zxf pip.1.0.2.tar.gz…

python5_python5

python2&python31.python2中print可加括号可不加括号&#xff0c;python3中print一定要加括号。2.python2中有range(),也有xrange(),python中只有range()。生成器。3.Python2中raw_input(),python3中input()。,,is赋值比较是否相等is 比较内存地址&#xff0c;id(内容)li1[…

单例设计模式1

单例 所谓单例设计模式,即时采取一定的方法保证在整个软件系统当中,对于某个类只能存在一个对象实例,并且该类只提供一个其对象实例的方法(静态方法) 恶汉式 优缺点说明: 优点:这种写法比较简单,就是在类装载的时候就完成实例化.避免了线程同步问题 缺点: 在类装载的时候就…

SJXXX串口扩展芯片 4串口芯片 UART串口芯片

SJXX串口扩展芯片1 概述SJ000是一款具备I2C总线/SPI总线/UART接口的四通道异步收发器件&#xff0c;通过模式选择使得该器件工作于以上任何一种主接口模式下。器件的四个通道UART可提供高达2Mbps的数据率&#xff0c;低功耗模式和睡眠电流。每个通道含有一个接收器和一个发送器…

MPLS服务合同到期了,是否该续签?

当考虑是否要更新现有MPLS服务合同以及续签多久时&#xff0c;你需要着眼于从价格到部署速度的方方面面。简而言之&#xff0c;如果你还没有获取一些与软件定义广域网有关技术的经验&#xff0c;即使用宽带或取代MPLS服务&#xff0c;那么你就没办法在未来几个月之内弃用MPLS。…

oracle rds 运维服务_从运维的角度分析使用阿里云数据库RDS的必要性–你不应该在阿里云上使用自建的MySQL/SQL Server/Oracle/PostgreSQL数据库...

开宗明义&#xff0c;你不应该在阿里云上使用自建的MySQL or SQL Server数据库&#xff0c;对了&#xff0c;还有Oracle or PostgreSQL数据库。云数据库 RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务。基于飞天分布式系统和全SSD盘高性能存储&…

单例设计模式2

恶汉式(静态代码块儿) 优缺点说明: 这种方式和上面的相似,只不过将类实例化的过程放在了静态代码块中,也是在类装载的时候,就执行静态代码块儿中的代码,初始化类的实例.优缺点和上面是一样的. 结论: 这种单例模式可用,可能 造成内存浪费 代码演示 package com.atguigu.pri…

FLV文件格式解析

FLV&#xff08;Flash Video&#xff09;是现在非常流行的流媒体格式&#xff0c;由于其视频文件体积轻巧、封装播放简单等特点&#xff0c;使其很适合在网络上进行应用&#xff0c;目前主流的视频网站无一例外地使用了FLV格式。另外由于当前浏览器与Flash Player紧密的结合&am…

华院数据宣晓华:传统零售商转型电商需攻克大数据三关

现在电商发展起来的节奏&#xff0c;使得大众更相信马云所言“五年内将没有线下销售”的可信度。面对这样的转变最该紧张的似乎是传统零售商了&#xff0c;日前在中美创新链接——大数据专题研讨会上&#xff0c;华院数据创始人、董事长宣晓华谈了传统零售商在转型过程中遭遇的…

部署到gcp_GCP 网络系统Andromeda --- 概述篇

这个系列总共有三篇&#xff0c;分别在&#xff1a;肖宏辉&#xff1a;GCP 网络系统Andromeda --- 概述篇肖宏辉&#xff1a;GCP 网络系统Andromeda --- 控制面肖宏辉&#xff1a;GCP 网络系统Andromeda --- 数据面最近看了Google在2018年的一篇NSDI文章&#xff0c;介绍他们的…

单例设计模式-懒汉式(线程不安全)

懒汉式(线程不安全) 优缺点说明 起到了Lazy Loading的效果,但是只能在单线程下使用 如果在多线程下, 一个线程进入if(singleton null)判断 语句块,还未来得及往下执行,另一个线程也通过了这个判断语句,这时便会产生多个实例. 所以在多线程的环境下,不可使用种方式 结论:在…

南海发展大数据产业 建设新型智慧城市

今天(9月5日)上午,佛山市南海区将迎来一大盛事——“南海大数据及工业互联网创新应用工作推进会”(以下简称“推进会”)召开,南海将与阿里巴巴、腾讯以及三大通信运营商等互联网、大数据巨头签订21个大数据建设亮点项目。同时,为吸引更多大数据产业集聚,南海将在推进会上同步发…

AMR音频编码器概述及文件格式分析

全称Adaptive Multi-Rate&#xff0c;自适应多速率编码&#xff0c;主要用于移动设备的音频&#xff0c;压缩比比较大&#xff0c;但相对其他的压缩格式质量比较差&#xff0c;由于多用于人声&#xff0c;通话&#xff0c;效果还是很不错的。 一、分类 1. AMR: 又称为AMR-NB&am…

查询自己OpenGL的版本信息

GLvoid PrintVersion() {const GLubyte* name glGetString(GL_VENDOR); //返回负责当前OpenGL实现厂商的名字const GLubyte* biaoshifu glGetString(GL_RENDERER); //返回一个渲染器标识符&#xff0c;通常是个硬件平台const GLubyte* OpenGLVersion glGetStr…

airpod蓝牙耳机音量大解决办法_关于AirPods的常见问题汇总 全面了解苹果AirPods无线耳机...

小编带来关于AirPods必知的24个问题&#xff0c;全面了解苹果AirPods无线耳机。苹果决定在iPhone7中抛弃3.5毫米耳机接口&#xff0c;这引发了许多争议和不解。苹果这样做的原因部分在于&#xff0c;希望人们转而使用无线耳机。因此苹果也推出了自主的无线耳机AirPods。对于无线…

单例设计模式-懒汉式(线程安全)

懒汉式(线程安全) 有缺点说明 解决了线程不安全问题 效率太低了,每个线程在想获得类的实例时候,执行getInstance()方法都要进行同步.而其实这个方法只执行了一次实例化代码就够了,后面的想获取该类实例,直接return就行了.方法进行同步效率太低 结论: 在实际开发中,不推荐使用…