运行时数据区概述

在这里插入图片描述
红色区域:多线程共享 垃圾回收基本都在堆空间(95%)完成,方法区(5%)一小部分

灰色区域:单独线程私有

一个jvm就是一个runtime实例,runtime对象相当于一个进程

进程是计算机分配内存的最小单位
jvm的线程

线程时一个程序里的运行单元,jvm允许一个应用有多个线程并行的执行

数据区

寄存器

每个线程都有自己的寄存器,生命周期跟随线程

寄存器用来存储下一条指令的地址,也就是即将要执行的代码。由执行引擎读取下一条指令
在这里插入图片描述

pc寄存器的两个常见问题

1.使用pc寄存器存储字节码指令地址有什么用?

因为cpu需要不停的切换各个线程,这个时候切换回来以后,就得知道接着从哪开始继续执行

2.pc寄存器为什么设置为线程私有?

为了能够准确记录各个线程正在执行的当前字节码指令地址,最好的办法就是为每一个线程都分配一个pc寄存器

虚拟机栈

tip:栈是运行时的单位,堆是存储的单位

概述:java虚拟机栈,早期也称java栈,每个线程创建时都会创建一个虚拟机栈,其内部保存一个个的栈帧,对应一次次的java方法调用,是线程私有的

在这里插入图片描述
一个线程对应一个java虚拟机栈

生命周期:生命周期和线程一致 随着线程的创建而创建 随着线程的消亡而消亡

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

局部变量(8种基本数据类型,引用对象的引用地址)

栈的优点:
  1. 栈是一种快速有效的分配内存方式,速度仅次于程序计数器
  2. 对于栈来说不存在垃圾回收方式(只有进栈弹栈的操作)

java虚拟机栈可以是动态的或者固定不变的

1.固定大小的虚拟机栈可能出现的问题:stackOverflowError异常

2.动态拓展可能出现的问题:outofMemoryError异常 没有足够的内存去扩容虚拟机栈

栈的存储单位
  1. 每个线程都有自己的栈,栈中的数据都是以栈帧的格式存在
  2. 在这个线程上正在执行的每个方法都各自对应一个栈帧
  3. 栈帧也是一个内存区块,是一个数据集,维系着方法执行过程中的各种数据信息
栈的执行原理
  1. 不同的线程中所包含的栈帧是不允许存在相互调用的,即不可能在一个栈帧之中引用另外一个线程的栈帧

  2. 如果当前方法调用了其他方法,方法返回之际,当前栈帧会传回此方法的执行结果给前一个栈帧,接着,虚拟机会丢弃当前栈帧,使得前一个栈帧重新成为当前栈帧

  3. java方法有两种返回函数的方式,一种是正常的函数返回,使用return指令;另外一种是抛出异常,不管使用哪种方式,都会导致栈帧被弹出

栈帧的内部结构

每个栈帧存储着:
在这里插入图片描述

局部变量表 (局部变量数组或本地变量表)

定义一个数字数组主要用于存储方法参数和定义在方法体内的局部变量,这些数据类型包括各类基本数据类型,对象引用以及返回值类型

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

  • 局部变量表,最基本的存储单位是slot(变量槽)、

  • 局部变量表追踪存放编译器可知的各种基本数据类型(8种),引用类型,返回值类型

  • 局部变量表里,32位以内的类型只占用一个slot,64位的类型占用两个slot
    byte,short,char在存储之前被转换为int,boolean也被转换为int,0代表false,非0代表true
    long和double则占据两个slot

  • 局部变量表是建立在线程的栈上的,是线程的私有数据,因此不存在数据的安全问题

  • 局部变量表所需的容量大小是在编译期确定下来的,在方法运行期间是不会改变局部变量表的大小

  • 在这里插入图片描述

      • 静态方法是不允许使用this,super两个变量的,因为不存在于当前方法的局部变量表中

      • 静态变量和局部变量的对比

        • 变量的分类:
          • 按数据类型来分:基本数据类型 引用数据类型
          • 按在类中的位置来分:成员变量 局部变量
          • 成员变量又可以分为两种: 类变量 实例变量
          • 类变量在使用之前都经历过默认初始化赋值
          • 实例对象:随着对象的创建,会在堆内存默认赋值
          • 局部变量在使用之前必须进行显式赋值
    1. 操作数栈

      操作数栈里面保存的就是 Java 虚拟机要执行的指令

      tip:栈可以用数组或链表实现

      作用:操作数栈,在方法执行的过程中,根据字节码指令,在栈中写入数据或提取数据,即入栈/出栈

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

      虽然操作数栈是由数组来实现的,但是不能根据索引来访问值,只能入栈/弹栈

      如果被调用的方法有返回值的话,其返回值会被压入当前的栈帧的操作数栈中,并更新pc寄存器中下一条需要执行的指令

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

      指向运行时常量池的方法引用
      tip:在字节码文件中,有专门一个区域存放常量叫做常量池
      字节码文件放在方法区中,所以常量池也在方法区中

    3. 方法返回地址 方法正常退出或异常退出的定义

    4. 一些附加信息

本地方法栈

本地方法栈是线程私有的

可以设置本地方法栈的长度

本地方法栈是存放调用本地方法时的引用

在hotspot中,本地方法栈和虚拟机栈合二为一了

tip:一个进程对应一个jvm实例 一个进程内部有多个线程

堆的核心描述:

  • 一个jvm实例(一个进程)只有一个堆内存
  • jvm堆区在jvm启动的时候即被创建,其空间大小也就确定了
  • 堆内存的大小是可以调节的
  • 堆可以在物理上不连续,逻辑上它应该被视为连续的
  • 所有的线程共享java堆,在这里还可以划分线程私有的缓冲区
  • 几乎所有的对象实例都在这里分配内存
  • 数组和对象可能永远不会存储在栈上,因为栈帧中保存引用,这个引用指向对象或者数组在堆中的位置
  • 方法结束后,堆中的数据不会马上被移除,仅仅在垃圾回收的时候才会被移除
  • 在这里插入图片描述
    一旦执行new,就申请空间,并创建对象

堆的核心概述:堆空间细分:

  • 新生代 伊甸园区 幸存者区 (from区,to区)
  • 老年代
  • 永久代

新生代对象分配与分配过程:
关于垃圾回收:频繁在新生区收集,很少在养老区收集,基本不在永久代(元空间的落地实现)收集

方法区

  • 栈,堆,方法区的交互关系

  • 在这里插入图片描述

  • 方法区的理解

    • 方法区与java堆一样,是各个线程共享的内存区域

    • 方法区在jvm启动的时候被创建,并且它的实际的物理内存空间中和Java堆区一样都可以是不连续的

    • 方法区的大小,跟堆空间一样,可以选择固定大小或者可以拓展

    • 方法区的大小决定了系统可以保存多少个类,如果系统定义了太多类,就会导致方法区溢出

    • 关闭jvm就会释放这个区域的内存

  • 方法区的内部结构
  • 在这里插入图片描述
    在这里插入图片描述

  • 类型信息

    • 这个类型直接父类的完整有效名
    • 这个类型的修饰符(public,abstract,final的某个子集)
    • 这个类型实现接口的一个有序列表(多实现)
  • 域信息

    • 域名称,域类型,域修饰符(public,private,protected,static,final,volatile,transient的某个子集)
  • 方法信息

    • 方法名称
    • 方法的返回类型
    • 方法参数的数量和类型(按顺序)
    • 方法的修饰符
    • 方法的字节码,操作数栈,局部变量表及下、大小
    • 异常表
  • 静态变量:

    • 静态变量和类关联在一起,随着类的加载而加载,它们成为类数据在逻辑上的一部分
    • 类变量被类的所有实例共享,即使没有类实例时也可以访问它
  • 全局常量:static final

  • 运行时常量池(方法区中的重要结构)
    • 运行时常量池是方法区的一部分
    • 常量池表是class文件的一部分,用于存放编译器生成的各种字面量与符号引用,这部分内容将在类加载后存放到方法区的运行时常量池
    • 运行时常量池,在加载类和接口到虚拟机后,就会创建对应的运行时常量池
    • jvm为每个加载的类型都维护了一个常量池,池中的数据项像数组项一样,是通过索引访问的
    • 运行时常量池中包含多种不同的常量,包括编译器就已经明确的数值字面量,也包括到运行期解析后才能获得的方法或者字段引用。此时不再是常量池中的符号地址了,这里换为真实地址
    • 运行时常量池,相对于calss文件的常量池最大的区别就是具有动态性
  • 在字节码文件中有一个常量池 (常量池是字节码文件的一部分):
    • 常量池包括各种字面量和对类型,域和方法的符号引用

    • 一个java源文件中的类,接口,编译之后产生一个字节码文件。而java中的字节码需要数据支持,通常这种数据会很大以至于不能直接存到字节码中,换一种方式,可以存到常量池,这个字节码包含了指向常量池的引用(一般都为String类型),在动态链接的时候会用到运行时常量池

      tip:字符串的拼接操作底层创建了一个StringBuilder,使用了append方法

    • 几种在常量池内存储的数据类型包括:

      - 数量值
      - 字符串值
      - 类引用
      - 字段引用
      - 方法引用
      
    • 常量池可以看作是一张表,虚拟机指令根据这张常量表找到要执行的类名,方法名,参数类型,字面量等类型

本地方法接口

本地方法接口的作用是融合不同的编程语言为java所用 本地方法由native修饰

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值