JVM基础知识学习(2)

本文详细解析了Java虚拟机栈的工作原理,包括栈帧结构、局部变量表(包括大小、数据类型和引用影响)、本地方法栈以及程序计数器的作用。同时,介绍了JVM的垃圾回收机制,区分了强引用、软引用和弱引用,并提及了虚引用的概念。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

作者简介:码上言


代表教程:Spring Boot + vue-element 开发个人博客项目实战教程


专栏内容:个人博客系统


我的文档网站:http://xyhwh-nav.cn/


微信公众号:码上言

Java虚拟机栈

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

  • 基于线程的,用来服务字节码指令的运行。每个线程有一个私有的栈,随着线程的创建而创建。栈里面存着的是一种叫“栈帧”的东西,每个方法会创建一个栈帧,栈帧中存放了局部变量表(基本数据类型和对象引用)、操作数栈、方法出口等信息。栈的大小可以固定也可以动态扩展。当栈调用深度大于JVM所允许的范围,会抛出StackOverflowError的错误,不过这个深度范围不是一个恒定的值。
  • 虚拟机栈除了上述错误外,还有另一种错误,那就是当申请不到空间时,会抛出 OutOfMemoryError。这里有一个小细节需要注意,catch 捕获的是 Throwable,而不是 Exception。因为 StackOverflowError 和 OutOfMemoryError 都不属于 Exception 的子类。
  • 栈的大小可以通过-Xss参数进行设置,当递归层次太深的时候,就会发生栈溢出。比如循环调用,递归等。
    JVM的运行是基于栈的,和C语言的栈类似,它的大多数数据都是在堆里面的,只有少部分运行时的数据存在于栈上。
局部变量表
  1. 大小固定,局部变量表是一组变量值存储空间,用于存放方法参数和方法内部定义的局部变量。在Java程序被编译成Class文件时,就在方法的Code属性的max_locals数据项中确定了该方法所需要分配的最大局部变量表的容量。
  2. Slot单位,局部变量表的容量以变量槽(Slot)为最小单位,32位虚拟机中一个Slot可以存放一个32位以内的数据类型(boolean、byte、char、short、int、float、reference和returnAddress八种)所以那些比较小的类型也占用32位内存(如boolean、byte、char、short),而double和long为64位数据类型,他们需要两个连续的Slot存储(64位虚拟机中可能只需要一个)
  3. 引用类型,reference类型(引用类型)虚拟机规范没有明确说明它的长度,但一般来说,虚拟机实现至少都应当能从此引用中直接或者间接地查找到对象在Java堆中的起始地址索引和方法区中的对象类型数据。
  4. Slot是可以重用的,当Slot中的变量超出了作用域,那么下一次分配Slot的时候,将会覆盖原来的数据。Slot对对象的引用会影响GC(要是被引用,将不会被回收)。
  5. 方法返回地址,returnAddress类型是为字节码指令jsr、jsr_w和ret服务的,它指向了一条字节码指令的地址。
  6. java文件编译后即生成指令集和常量池。
  7. 动态链接就是将指令中的符号引用转化为真实的方法地址。(依据常量池)
完成出口
  • 正常完成出口和异常完成出口的区别在于:通过异常完成出口退出的不会给他的上层调用者产生任何的返回值。
  • 方法返回地址即为被调用方法执行结束后与调用方法交接时需要用到的内存结构。记录被调用方法结束后,调用处的下一条指令。
  • 动态链接和方法返回地址及一些附加信息有些汇总称为:栈帧数据区。

本地方法栈

  1. 一个支持native方法调用的JVM实现,需要有这样一个数据区,就是本地方法栈,Java官方对于本地方法的定义为methods written in a language other than the Java programming language,就是使用非Java语言实现的方法,但是通常我们指的一般为C或者C++,因此这个栈也有着C栈这一称号。一个不支持本地方法执行的JVM没有必要实现这个数据区域。本地方法栈基本和JVM栈一样,其大小也是可以设置为固定值或者动态增加,因此也会对应抛出StackOverflowError和OutOfMemoryError错误。
  2. 在HotSopt虚拟机中直接就把本地方法栈和Java栈合二为一。

程序计数器

在通用的计算机体系中,程序计数器用来记录当前正在执行的指令,在JVM中也是如此。程序计数器是线程私有,所以当一个新的线程创建时,程序计数器也会创建。由于Java是支持多线程,Java中的程序计数器用来记录当前线程中正在执行的指令。如果当前正在执行的方法是本地方法,那么此刻程序计数器的值为undefined。注意这个区域是唯一一个不抛出OutOfMemoryError的运行时数据区。

JVM垃圾回收

在这里插入图片描述
JVM采用的是可达性分析算法。
JVM是通过GC Roots来判定对象的存活的。从GC Roots向下追溯、搜索,会产生一个叫做Reference Chain的链条。当一个对象不能和任何一个GC Root产生关系,就判定为垃圾。
GC Roots

  • 活动线程相关的各种引用,比如虚拟机栈中栈帧里的引用。
  • 类的静态变量的引用。
  • JNI引用等。
  • Java线程中,当前所有正在被调用的方法的引用类型参数、局部变量、临时值等。也就是与我们栈帧相关的各种引用。
  • 所有当前被加载的Java类。
  • Java类的引用类型静态变量。
  • 运行时常量池里的引用类型常量(String或Class类型)。
  • JVM内部数据结构的一些引用,比如sun.jvm.hotspot.memory.Universe类。
  • 用于同步的监控对象,比如调用了对象的wait()方法。
  • JNI handles,包括global handles和local handles。
强引用、软引用、弱引用、虚引用?
  • 普通的对象引用关系就是强引用。
  • 软引用用于维护一些可有可无的对象。只有在内存不足时,系统则会回收软引用对象,如果回收了软引用对象之后仍然没有足够的内存,才会抛出内存溢出异常。
  • 弱引用对象相比较软引用,要更加无用一些,它拥有更短的生命周期。当JVM进行垃圾回收时,无论内存是否充足,都会回收被弱引用关联的对象。
  • 虚引用是一种形同虚设的引用,在现实场景中用的不是很多,它主要用来跟踪对象被垃圾回收的活动。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码上言

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值