JVM深入原理(七)(一):运行时数据区

简介: 栈的介绍:Java虚拟机栈采用栈的数据结构来管理方法调用中的基本数据,先进后出,每一个方法的调用使用一个栈帧来保存栈的组成:栈:一个线程运行所需要的内存空间,一个栈由多个栈帧组成栈帧:一个方法运行所需要的内存空间活动栈帧:一个线程中只能有一个活动栈帧栈的生命周期:栈随着线程的创建而创建,而回收会在线程销毁时进行栈的执行流程:栈帧压入栈内执行方法执行完毕释放内存若方法间存在调用,那么会压入被调用方法入栈,执行完后释放内存,再执行当前方法,直到执行完毕,释放所有内存。

JVM系列文章

  1. 深入理解JVM,包含字节码文件,内存结构,垃圾回收,类的声明周期,类加载器_eden used total max-CSDN博客
  2. JVM深入原理(一+二):JVM概述和JVM功能-CSDN博客
  3. JVM深入原理(三+四):JVM组成和JVM字节码文件-CSDN博客
  4. JVM深入原理(五):JVM组成和JVM字节码文件-CSDN博客
  5. JVM深入原理(六)(一):JVM类加载器-CSDN博客
  6. JVM深入原理(六)(二):双亲委派机制-CSDN博客
  7. JVM深入原理(七)(一):运行时数据区-CSDN博客
  8. JVM深入原理(七)(二):运行时数据区-CSDN博客
  9. JVM深入原理(八)(一):垃圾回收-CSDN博客
  10. JVM深入原理(八)(二):垃圾回收-CSDN博客

目录

7. JVM运行时数据区

7.1. 运行时数据区-总览

7.2. 运行时数据区-查看内存对象

7.3. 运行时数据区-程序计数器

7.3.1. 程序计数器-作用

7.3.2. 字节码指令执行流程

7.4. 运行时数据区-Java虚拟机栈

7.4.1. 栈-概述

7.4.2. 栈帧-组成

7.4.2.1. 栈帧-帧数据

7.4.2.2. 栈帧-操作数栈

7.4.2.3. 栈帧-局部变量表

7.4.3. 栈-执行流程

7.4.4. 栈-内存溢出

7.4.5. 栈-设置栈内存大小

7.4.6. 栈相关问题

7.4.6.1. 垃圾回收是否涉及栈内存?

7.4.6.2. 栈内存分配越大越好吗?

7.4.6.3. 方法内的局部变量是否线程安全?


7. JVM运行时数据区

7.1. 运行时数据区-总览

  • 运行时数据区的概念:是JVM运行Java程序过程中管理内存的区域
  • 运行时数据区的组成总览

    image.gif 编辑
  • 线程不共享的含义:每个线程创建后,内部都会创建自己的程序计数器,Java虚拟机栈,本地方法栈对应的数据,自己维护数据,不共享,安全性高,当线程回收时这些区域的内存也随着回收
  • 线程共享的含义:每个线程都可以访问方法区和堆中的数据,是共享的,是线程不安全的

7.2. 运行时数据区-查看内存对象

  • JDK自带的hsdb工具查看JVM内存信息,工具位于JDK安装目录下lib文件夹中的sa-jdi.jar文件中
  • 启动命令:java -cp sa-jdi.jar sun.jvm.hotspot.HSDB

    image.gif 编辑

7.3. 运行时数据区-程序计数器

7.3.1. 程序计数器-作用

  • 程序计数器的作用:程序计数器(Program Counter Register)也叫PC寄存器,内部存放了接下来要执行的字节码指令的地址,交给解释器执行,可以实现分支,跳转,异常等逻辑,在多线程情况下,JVM需要程序计数器记录CPU切换前的地址并继续执行,程序计数器只存储一个固定长度的内存地址,不会内存溢出

    image.gif 编辑

    image.gif 编辑

7.3.2. 字节码指令执行流程

  • 字节码指令执行的流程:字节码指令和偏移量最初保存在字节码文件中,类加载器将字节码文件读取到内存之后,字节码指令也就保存在内存中原文件中的偏移量也被替换成内存地址,每一行字节码指令都有自己的地址,字节码指令最终要交给解释器去执行,所以解释器就必须知道需要解释的字节码指令在哪,这个地址就由程序计数器交给解释器

    image.gif 编辑

程序计数器在物理上的实现是寄存器,是整个CPU里读取速度最快的单元

程序计数器也就是Java对物理硬件的屏蔽和抽象

7.4. 运行时数据区-Java虚拟机栈

7.4.1. 栈-概述

  • 栈的介绍:Java虚拟机栈采用栈的数据结构来管理方法调用中的基本数据,先进后出,每一个方法的调用使用一个栈帧来保存
  • 栈的组成:

    image.gif 编辑
  • 栈:一个线程运行所需要的内存空间,一个栈由多个栈帧组成
  • 栈帧:一个方法运行所需要的内存空间
  • 活动栈帧:一个线程中只能有一个活动栈帧
  • 栈的生命周期:栈随着线程的创建而创建,而回收会在线程销毁时进行
  • 栈的执行流程:
  1. 栈帧压入栈内执行方法
  2. 执行完毕释放内存
  3. 若方法间存在调用,那么会压入被调用方法入栈,执行完后释放内存,再执行当前方法,直到执行完毕,释放所有内存

    image.gif 编辑

7.4.2. 栈帧-组成

7.4.2.1. 栈帧-帧数据

  • 帧数据的作用:包含动态链接,方法出口,异常表的引用
  • 动态链接:保存的是符号引用到内存地址的映射关系,主要保存的是其他类的属性或方法,字节码指令运行时可以根据动态链接快速获取到运行时常量池的数据
  • 方法出口:方法出口指的是方法在正确或者异常结束时,当前栈帧会被弹出,同时程序计数器应该指向上一个栈帧中的下一条指令的地址。所以在当前栈帧中,需要存储此方法出口的地址
  • 异常表:异常表存放的是代码中异常的处理信息,包含了try代码块和catch代码块执行后跳转到的字节码指令位置。

7.4.2.2. 栈帧-操作数栈

  • 操作数栈作用:存储方法执行过程中需要计算的操作数以及操作结果.
  • 计算过程:从操作数栈中弹出操作数、执行运算操作,并将结果重新压入操作数栈中
  • 操作数栈的生命周期:当方法执行时,创建一个对应的栈帧,栈帧中包括了该方法操作数栈,当方法执行结束时,对应的栈帧也会被销毁,在编译期就可以确定操作数栈的最大深度

7.4.2.3. 栈帧-局部变量表

  • 局部变量表的作用:存储方法执行过程中所有的局部变量,字节码文件编译时就确定了局部变量表的内容
  • 字节码文件中的局部变量表:每个局部变量表有编号和生效范围

    image.gif 编辑
  • 栈帧中的局部变量表:栈帧中的局部变量表是一个数组,数组中每一个位置称之为槽(slot),long和double类型占用两个槽,其他类型占用一个槽。

    image.gif 编辑
  • 局部变量表保存的内容:实例方法的this对象(0号位置),方法的参数,方法体中声明的局部变量。
  • 局部变量表的运行优化机制:局部变量表中的槽是可以复用的,一旦某个变量失效了(代码块中的变量执行完毕),当前槽就可以再次使用

    image.gif 编辑
  • 局部变量表的生命周期:当方法执行时,创建一个对应的栈帧,栈帧中包括了该局部变量表,当方法执行结束时,对应的栈帧也会被销毁

7.4.3. 栈-执行流程

执行流程演示:

  1. 栈内随着方法调用,栈帧一个个被压入栈内,随着方法执行完毕,方法一个个被弹栈而出,定义的变量的内存空间也随着方法执行完毕释放


  1. image.gif 编辑


  2. image.gif 编辑

7.4.4. 栈-内存溢出

  • 栈内存溢出的情况:Java虚拟机栈如果栈帧过多,占用内存超过栈内存可以分配的最大大小就会出现内存溢出,此时会出现StackOverflowError的异常
  • 栈帧过多:递归调用,死锁,死循环


  • image.gif 编辑
  • 栈帧过大

7.4.5. 栈-设置栈内存大小

  • 设置栈大小参数:-Xss或-XX:ThreadStackSize=1024
  • 语法:-Xss栈大小或-XX:ThreadStackSize=栈大小
  • 单位:字节(默认,必须是1024的倍数)、k或者K(KB)、m或者M(MB)、g或者G(GB)
  • 栈最大最小值:jdk8中最大180k,最大1024mb


  • image.gif 编辑

7.4.6. 栈相关问题

7.4.6.1. 垃圾回收是否涉及栈内存?

不涉及,每次方法执行完毕之后,栈内存就会直接释放,并不会堆积内存,垃圾回收的是堆内存中不使用的内存

7.4.6.2. 栈内存分配越大越好吗?

在程序执行时,可以通过-Xss size指定栈内存的大小,默认大小为1024KB也就是1M,一个线程使用一个栈内存,如果栈内存设置过大,那么单个线程占用的内存就会过大,在总内存空间一定的情况下,这样反而减少了线程数量,降低了性能

7.4.6.3. 方法内的局部变量是否线程安全?

要判定一个变量是否为线程安全,就要查看这个变量是为多个线程共有的还是一个线程私有的.

要判断方法中的成员变量是否为线程安全,要查看这个成员变量是否脱离了方法的作用范围,有两种情况是线程不安全的:

  • 变量作为参数传入方法中,这样其他线程就可能访问到该变量,所以不是线程安全的
  • 变量作为返回值返回,这样其他线程可能拿到该变量并操作,所以不是线程安全的
目录
相关文章
|
1月前
|
Oracle Java 关系型数据库
JVM深入原理(一+二):JVM概述和JVM功能
JVM全称是Java Virtual Machine-Java虚拟机JVM作用:本质上是一个运行在计算机上的程序,职责是运行Java字节码文件,编译为机器码交由计算机运行。
59 0
|
1月前
|
Arthas 存储 Java
JVM深入原理(三+四):JVM组成和JVM字节码文件
目录3. JVM组成3.1. 组成-运行时数据区3.2. 组成-类加载器3.3. 组成-执行引擎3.4. 组成-本地接口4. JVM字节码文件4.1. 字节码文件-组成4.1.1. 组成-基础信息4.1.1.1. 基础信息-魔数4.1.1.2. 基础信息-主副版本号4.1.2. 组成-常量池4.1.3. 组成-方法4.1.3.1. 方法-工作流程4.1.4. 组成-字段4.1.5. 组成-属性4.2. 字节码文件-查看工具4.2.1. javap4.2.2. jclasslib4.2.3. 阿里Arthas
36 0
|
1月前
|
存储 安全 Java
JVM深入原理(五):JVM组成和JVM字节码文件
类的生命周期概述:类的生命周期描述了一个类加载,使用,卸载的整个过类的生命周期阶段:类的声明周期主要分为五个阶段:加载->连接->初始化->使用->卸载,其中连接中分为三个小阶段验证->准备->解析。
27 0
|
1月前
|
Arthas Java 测试技术
JVM深入原理(六)(一):JVM类加载器
目录6. JVM类加载器6.1. 类加载器-概述6.2. 类加载器-执行流程6.3. 类加载器-分类(JDK8)6.3.1. JVM底层实现的类加载器6.3.1.1. 启动类加载器6.3.2. Java代码实现类的加载器6.3.2.1. 扩展类加载器6.3.2.2. 应用程序类加载器6.4. 类加载器-Arthas查看类加载器
29 0
|
1月前
|
Java 关系型数据库 MySQL
JVM深入原理(六)(二):双亲委派机制
自定义类加载器打破双亲委派机制的方法:复写ClassLoader中的loadClass方法常见问题:要加载的类名如果是以java.开头,则会抛出安全性异常加载自定义的类都会有一个共同的父类Object,需要在代码中交由父类加载器去加载自定义类加载器不手动指定parent会默认指定应用类加载两个自定义类加载器加载同一个类会被认为是两个对象,只有相同的类加载器+想通的类限定名才会被认为是一个对象。
39 0
|
1月前
|
存储 缓存 安全
JVM深入原理(七)(二):运行时数据区
堆的作用:存放对象的内存空间,它是空间最大的一块内存区域.栈上的局部变量表中,可以存放堆上对象的引用。静态变量也可以存放堆对象的引用,通过静态变量就可以实现对象在线程之间共享。堆的特点:线程共享:堆中的对象都需要考虑线程安全的问题垃圾回收:堆有垃圾回收机制,不再引用的对象就会被回收方法区的概述:方法区是存放基础信息的位置,线程共享,主要包括:类的元信息:保存了所有类的基本信息运行时常量池:保存了字节码文件中的常量池内容静态常量池:字节码文件通过编号查表的方式找到常量。
31 0
|
1月前
|
Arthas 存储 算法
深入理解JVM,包含字节码文件,内存结构,垃圾回收,类的声明周期,类加载器
JVM全称是Java Virtual Machine-Java虚拟机JVM作用:本质上是一个运行在计算机上的程序,职责是运行Java字节码文件,编译为机器码交由计算机运行类的生命周期概述:类的生命周期描述了一个类加载,使用,卸载的整个过类的生命周期阶段:类的声明周期主要分为五个阶段:加载->连接->初始化->使用->卸载,其中连接中分为三个小阶段验证->准备->解析类加载器的定义:JVM提供类加载器给Java程序去获取类和接口字节码数据类加载器的作用:类加载器接受字节码文件。
207 55
|
2月前
|
Arthas 监控 Java
Arthas memory(查看 JVM 内存信息)
Arthas memory(查看 JVM 内存信息)
125 6
|
5月前
|
存储 设计模式 监控
快速定位并优化CPU 与 JVM 内存性能瓶颈
本文介绍了 Java 应用常见的 CPU & JVM 内存热点原因及优化思路。
797 166
|
3月前
|
存储 缓存 算法
JVM简介—1.Java内存区域
本文详细介绍了Java虚拟机运行时数据区的各个方面,包括其定义、类型(如程序计数器、Java虚拟机栈、本地方法栈、Java堆、方法区和直接内存)及其作用。文中还探讨了各版本内存区域的变化、直接内存的使用、从线程角度分析Java内存区域、堆与栈的区别、对象创建步骤、对象内存布局及访问定位,并通过实例说明了常见内存溢出问题的原因和表现形式。这些内容帮助开发者深入理解Java内存管理机制,优化应用程序性能并解决潜在的内存问题。
222 29
JVM简介—1.Java内存区域