当前位置: 首页 > news >正文

深入理解 JVM 的栈帧结构

🧑 博主简介:CSDN博客专家历代文学网(PC端可以访问:https://literature.sinhy.com/#/literature?__c=1000,移动端可微信小程序搜索“历代文学”)总架构师,15年工作经验,精通Java编程高并发设计Springboot和微服务,熟悉LinuxESXI虚拟化以及云原生Docker和K8s,热衷于探索科技的边界,并将理论知识转化为实际应用。保持对新技术的好奇心,乐于分享所学,希望通过我的实践经历和见解,启发他人的创新思维。在这里,我希望能与志同道合的朋友交流探讨,共同进步,一起在技术的世界里不断学习成长。
技术合作请加本人wx(注明来自csdn):foreast_sea

在这里插入图片描述


在这里插入图片描述

文章目录

  • 深入理解 JVM 的栈帧结构
    • 局部变量表
    • 操作数栈
    • 动态链接
    • 方法返回地址
    • 附加信息
    • StackOverflowError
    • 小结

深入理解 JVM 的栈帧结构

栈帧是运行时数据区中用于支持虚拟机进行方法调用和方法执行的数据结构。每一个方法从调用开始到执行完成,都对应着一个栈帧在虚拟机栈/本地方法栈里从入栈到出栈的过程。

本文我们就来详细地探讨 JVM 的栈帧结构,好让大家对栈帧有一个更加清晰的认知。

我们从下面这幅图开始讲起。

Java 的源码文件经过编译器编译后会生成字节码文件,然后由 JVM 的类加载器进行加载,再交给执行引擎执行。在执行过程中,JVM 会划出一块内存空间来存储程序执行期间所需要用到的数据,这块空间一般被称为运行时数据区。

栈帧(Stack Frame)是运行时数据区中用于支持虚拟机进行方法调用和方法执行的数据结构。每一个方法从调用开始到执行完成,都对应着一个栈帧在虚拟机栈/本地方法栈里从入栈到出栈的过程。

本地方法,也就是 native 方法,我们前面有详细地讲过,由 C/C++ 实现。

每一个栈帧都包括了局部变量表、操作数栈、动态链接、方法返回地址和一些额外的附加信息。

在编译程序代码时,栈帧中需要多大的局部变量表,多深的操作数栈都已经完全确定了,并且写入到方法表的 Code 属性之中。

方法表、局部变量表我们在讲字节码的时候有讲过,可以戳链接再回头看一下,这篇内容也会继续盘一盘。

一个线程中的方法调用链可能会很长,很多方法都处于执行状态。在当前线程中,位于栈顶的栈帧被称为当前栈帧(Current Stack Frame),与这个栈帧相关联的方法成为当前方法。执行引擎运行的所有字节码指令都是对当前栈帧进行操作,在概念模型上,栈帧的结构如下图所示:

局部变量表

局部变量表(Local Variables Table)用来保存方法中的局部变量,以及方法参数。当 Java 源代码文件被编译成 class 文件的时候,局部变量表的最大容量就已经确定了。

我们来看这样一段代码。

public class LocalVaraiablesTable {private void write(int age) {String name = "沉默王二";}
}

write() 方法有一个参数 age,一个局部变量 name。

然后用 Intellij IDEA 的 jclasslib 查看一下编译后的字节码文件 LocalVaraiablesTable.class。可以看到 write() 方法的 Code 属性中,Maximum local variables(局部变量表的最大容量)的值为 3。

按理说,局部变量表的最大容量应该为 2 才对,一个 age,一个 name,为什么是 3 呢?

当一个成员方法(非静态方法)被调用时,第 0 个变量其实是调用这个成员方法的对象引用,也就是那个大名鼎鼎的 this。调用方法 write(18),实际上是调用 write(this, 18)

点开 Code 属性,查看 LocalVaraiableTable 就可以看到详细的信息了。

第 0 个是 this,类型为 LocalVaraiablesTable 对象;第 1 个是方法参数 age,类型为整型 int;第 2 个是方法内部的局部变量 name,类型为字符串 String。

当然了,局部变量表的大小并不是方法中所有局部变量的数量之和,它与变量的类型和变量的作用域有关。当一个局部变量的作用域结束了,它占用的局部变量表中的位置就被接下来的局部变量取代了。

来看下面这段代码。

public static void method() {// ①if (true) {// ②String name = "沉默王二";}// ③if(true) {// ④int age = 18;}// ⑤
}
  • method() 方法的局部变量表大小为 1,因为是静态方法,所以不需要添加 this 作为局部变量表的第一个元素;
  • ②的时候局部变量有一个 name,局部变量表的大小变为 1;
  • ③的时候 name 变量的作用域结束;
  • ④的时候局部变量有一个 age,局部变量表的大小为 1;
  • ⑤的时候局 age 变量的作用域结束;

关于局部变量的作用域,《Effective Java》 中的第 57 条建议:

将局部变量的作用域最小化,可以增强代码的可读性和可维护性,并降低出错的可能性。

在此,我还有一点要提醒大家。为了尽可能节省栈帧耗用的内存空间,局部变量表中的槽是可以重用的,就像 method() 方法演示的那样,这就意味着,合理的作用域有助于提高程序的性能。是不是很有意思?

局部变量表的容量以槽(slot)为最小单位,一个槽可以容纳一个 32 位的数据类型(比如说 int,当然了,《Java 虚拟机规范》中没有明确指出一个槽应该占用的内存空间大小,但我认为这样更容易理解),像 float 和 double 这种明确占用 64 位的数据类型会占用两个紧挨着的槽。

来看下面的代码。

public void solt() {double d = 1.0;int i = 1;
}

用 jclasslib 可以查看到,solt() 方法的 Maximum local variables 的值为 4。

为什么等于 4 呢?带上 this 也就 3 个呀?

查看 LocalVaraiableTable 就明白了,变量 i 的下标为 3,也就意味着变量 d 占了两个槽。

操作数栈

同局部变量表一样,操作数栈(Operand Stack)的最大深度也在编译的时候就确定了,被写入到了 Code 属性的 maximum stack size 中。当一个方法刚开始执行的时候,操作数栈是空的,在方法执行过程中,会有各种字节码指令往操作数栈中写入和取出数据,也就是入栈和出栈操作。

来看下面这段代码。

public class OperandStack {public void test() {add(1,2);}private int add(int a, int b) {return a + b;}
}

OperandStack 类共有 2 个方法,test() 方法中调用了 add() 方法,传递了 2 个参数。用 jclasslib 可以看到,test() 方法的 maximum stack size 的值为 3。

这是因为调用成员方法的时候会将 this 和所有参数压入栈中,调用完毕后 this 和参数都会一一出栈。通过 「Bytecode」 面板可以查看到对应的字节码指令。

  • aload_0 用于将局部变量表中下标为 0 的引用类型的变量,也就是 this 加载到操作数栈中;
  • iconst_1 用于将整数 1 加载到操作数栈中;
  • iconst_2 用于将整数 2 加载到操作数栈中;
  • invokevirtual 用于调用对象的成员方法;
  • pop 用于将栈顶的值出栈;
  • return 为 void 方法的返回指令。

字节码指令前面我们已经讲过了,忘记的球友可以再回顾一下。再来看一下 add() 方法的字节码指令。

  • iload_1 用于将局部变量表中下标为 1 的 int 类型变量加载到操作数栈上(下标为 0 的是 this);
  • iload_2 用于将局部变量表中下标为 2 的 int 类型变量加载到操作数栈上;
  • iadd 用于 int 类型的加法运算;
  • ireturn 为返回值为 int 的方法返回指令。

操作数中的数据类型必须与字节码指令匹配,以上面的 iadd 指令为例,该指令只能用于整型数据的加法运算,它在执行的时候,栈顶的两个数据必须是 int 类型的,不能出现一个 long 型和一个 double 型的数据进行 iadd 命令相加的情况。

动态链接

每个栈帧都包含了一个指向运行时常量池中该栈帧所属方法的引用,持有这个引用是为了支持方法调用过程中的动态链接(Dynamic Linking)。

图片来源于网络,作者浣熊say

①、前面我们就讲过,方法区是 JVM 的一个运行时内存区域,属于逻辑定义,不同版本的 JDK 都有不同的实现,但主要的作用就是用于存储已被虚拟机加载的类信息、常量、静态变量,以及即时编译器编译后的代码等。

②、运行时常量池(Runtime Constant Pool)是方法区的一部分,用于存放编译期生成的各种字面量和符号引用——在类加载后进入运行时常量池。关于方法区我们也会在后面进行详细地讲解。

来看下面这段代码。

public class DynamicLinking {static abstract class Human {protected abstract void sayHello();}static class Man extends Human {@Overrideprotected void sayHello() {System.out.println("男人哭吧哭吧不是罪");}}static class Woman extends Human {@Overrideprotected void sayHello() {System.out.println("山下的女人是老虎");}}public static void main(String[] args) {Human man = new Man();Human woman = new Woman();man.sayHello();woman.sayHello();man = new Woman();man.sayHello();}
}

大家对 Java 重写有了解的话,应该能看懂这段代码的意思。Man 类和 Woman 类继承了 Human 类,并且重写了 sayHello() 方法。来看一下运行结果:

男人哭吧哭吧不是罪
山下的女人是老虎
山下的女人是老虎

这个运行结果很好理解,man 的引用类型为 Human,但指向的是 Man 对象,woman 的引用类型也为 Human,但指向的是 Woman 对象;之后,man 又指向了新的 Woman 对象。

从面向对象编程的角度,从多态的角度,我们对运行结果是很好理解的,但站在 Java 虚拟机的角度,它是如何判断 man 和 woman 该调用哪个方法的呢?

用 jclasslib 看一下 main 方法的字节码指令。

  • 第 1 行:new 指令创建了一个 Man 对象,并将对象的内存地址压入栈中。
  • 第 2 行:dup 指令将栈顶的值复制一份并压入栈顶。因为接下来的指令 invokespecial 会消耗掉一个当前类的引用,所以需要复制一份。
  • 第 3 行:invokespecial 指令用于调用构造方法进行初始化。
  • 第 4 行:astore_1,Java 虚拟机从栈顶弹出 Man 对象的引用,然后将其存入下标为 1 局部变量 man 中。
  • 第 5、6、7、8 行的指令和第 1、2、3、4 行类似,不同的是 Woman 对象。
  • 第 9 行:aload_1 指令将第局部变量 man 压入操作数栈中。
  • 第 10 行:invokevirtual 指令调用对象的成员方法 sayHello(),注意此时的对象类型为 com/itwanger/jvm/DynamicLinking$Human
  • 第 11 行:aload_2 指令将第局部变量 woman 压入操作数栈中。
  • 第 12 行同第 10 行。

注意,从字节码的角度来看,man.sayHello()(第 10 行)和 woman.sayHello()(第 12 行)的字节码是完全相同的,但我们都知道,这两句指令最终执行的目标方法并不相同。

究竟发生了什么呢?

还得从 invokevirtual 这个指令着手,看它是如何实现多态的。根据《Java 虚拟机规范》,invokevirtual 指令在运行时的解析过程可以分为以下几步:

  • ①、找到操作数栈顶的元素所指向的对象的实际类型,记作 C。
  • ②、如果在类型 C 中找到与常量池中的描述符匹配的方法,则进行访问权限校验,如果通过则返回这个方法的直接引用,查找结束;否则返回 java.lang.IllegalAccessError 异常。
  • ③、否则,按照继承关系从下往上一次对 C 的各个父类进行第二步的搜索和验证。
  • ④、如果始终没有找到合适的方法,则抛出 java.lang.AbstractMethodError 异常。

也就是说,invokevirtual 指令在第一步的时候就确定了运行时的实际类型,所以两次调用中的 invokevirtual 指令并不是把常量池中方法的符号引用解析到直接引用上就结束了,还会根据方法接受者的实际类型来选择方法版本,这个过程就是 Java 重写的本质。我们把这种在运行期根据实际类型确定方法执行版本的过程称为动态链接

方法返回地址

当一个方法开始执行后,只有两种方式可以退出这个方法:

  • 正常退出,可能会有返回值传递给上层的方法调用者,方法是否有返回值以及返回值的类型根据方法返回的指令来决定,像之前提到的 ireturn 用于返回 int 类型,return 用于 void 方法;还有其他的一些,lreturn 用于 long 型,freturn 用于 float,dreturn 用于 double,areturn 用于引用类型。
  • 异常退出,方法在执行的过程中遇到了异常,并且没有得到妥善的处理,这种情况下,是不会给它的上层调用者返回任何值的。

无论是哪种方式退出,在方法退出后,都必须返回到方法最初被调用时的位置,程序才能继续执行。一般来说,方法正常退出的时候,PC 计数器的值会作为返回地址,栈帧中很可能会保存这个计数器的值,异常退出时则不会。

PC 计数器:JVM 运行时数据区的一部分,跟踪当前线程执行字节码的位置。

方法退出的过程实际上等同于把当前栈帧出栈,因此接下来可能执行的操作有:恢复上层方法的局部变量表和操作数栈,把返回值(如果有的话)压入调用者栈帧的操作数栈中,调整 PC 计数器的值,找到下一条要执行的指令等。

附加信息

虚拟机规范允许具体的虚拟机实现增加一些规范里没有描述的信息到栈帧中,例如与调试相关的信息,这部分信息完全取决于具体的虚拟机实现。实际开发中,一般会把动态连接、方法返回地址与其他附加信息全部归为一类,成为栈帧信息。

StackOverflowError

下面这段代码在运行的时候会抛出 StackOverflowError 异常。

public class StackOverflowErrorTest {public static void main(String[] args) {StackOverflowErrorTest test = new StackOverflowErrorTest();test.testStackOverflowError();}public void testStackOverflowError() {testStackOverflowError();}
}

我们来看一下异常的堆栈信息。

之所以抛出 StackOverflowError 异常,是因为在执行 testStackOverflowError() 方法的时候,会创建一个栈帧,然后调用 testStackOverflowError() 方法,又会创建一个栈帧,然后调用 testStackOverflowError() 方法,又会创建一个栈帧……这样一直循环下去,直到栈内存溢出。

我们来简单改造了一下代码,看一下异常的堆栈信息。

public class StackOverflowErrorTest1 {private static AtomicInteger count = new AtomicInteger(0);public static void main(String[] args) {while (true) {testStackOverflowError();}}public static void testStackOverflowError() {System.out.println(count.incrementAndGet());testStackOverflowError();}
}

在 10924 次的时候,抛出了 StackOverflowError 异常。大家可以试试自己的本地环境,看多少次的时候会抛出异常。

小结

栈帧是 JVM 中用于方法执行的数据结构,每当一个方法被调用时,JVM 会为该方法创建一个栈帧,并在方法执行完毕后销毁。

  • 局部变量表:存储方法的参数和局部变量,由基本数据类型或对象引用组成。
  • 操作数栈:后进先出(LIFO)的栈结构,用于存储操作数和中间计算结果。
  • 动态链接:关联到方法所属类的常量池,支持动态方法调用。
  • 方法返回地址:记录方法结束后控制流应返回的位置。

栈帧是线程私有的,每个线程有自己的 JVM 栈。方法调用时,新栈帧被推入栈顶;方法完成后,栈帧出栈。

栈帧的局部变量表的大小和操作数栈的最大深度在编译时就已确定。栈空间不足时可能引发 StackOverflowError。理解栈帧对于深入理解 Java 程序的运行机制至关重要。

相关文章:

深入理解 JVM 的栈帧结构

🧑 博主简介:CSDN博客专家,历代文学网(PC端可以访问:https://literature.sinhy.com/#/literature?__c1000,移动端可微信小程序搜索“历代文学”)总架构师,15年工作经验,…...

爬虫基础之HTTP基本原理

URL和URI 我们先了解一下 URI和 URL。URI的全称为 Uniform Resource ldentifer,即统一资源标志符;URL的全称为 Universal Resource Locator,即统一资源定位符。它们是什么意思呢?举例来说,https:/github.com/favicon.ico 既是一个 URI,也是…...

PyQt5:一个逗号引发的闪退血案

【日常小计】 在开发PyQt5程序时,调用了一个写入excel表格的后端方法,但是每次打开页面点击对应的动作,窗口就会闪退,而且Python后台也没有提示出任何的异常堆栈,后来经过在后端一点一点的单点测试,终于发…...

python学opencv|读取图像(五)读取灰度图像像素

【1】引言 前序学习了图像的基本读取,掌握了imread()、imshow()和imwrite()函数的基本功能和使用技巧,参考文章链接为: python学opencv|读取图像-CSDN博客 然后陆续掌握了彩色图像保存、图像放大和缩小以及对imshow()函数的大胆尝试技巧&a…...

LiDAR点云 反射强度 常见物体反射强度

1.激光点云发射的点无法全部被反射回来的原因 激光点云发射的点无法全部被反射回来的原因主要包括以下几点: 目标物表面特性:某些物体表面具有高反射率,导致激光雷达接收到的反射能量过强,从而产生噪点,影响点云数据的…...

零基础微信小程序开发——WXML 模板语法之事件绑定(保姆级教程+超详细)

🎥 作者简介: CSDN\阿里云\腾讯云\华为云开发社区优质创作者,专注分享大数据、Python、数据库、人工智能等领域的优质内容 🌸个人主页: 长风清留杨的博客 🍃形式准则: 无论成就大小,…...

qt QNetworkAccessManager详解

1、概述 QNetworkAccessManager是QtNetwork模块中的一个核心类,它允许应用程序发送网络请求并接收响应。该类是网络通信的基石,提供了一种方便的方式来处理常见的网络协议,如HTTP、HTTPS等。QNetworkAccessManager对象持有其发送的请求的通用…...

在2023idea中如何创建SpringBoot

目录 一.下载和安装 Maven 1.前往 https://maven.apache.org/download.cgi 下载最新版的 Maven 程序 2.将文件解压到D:Program FilesApachemaven目录 3.新建环境变量MAVEN_HOME,赋值D:Program FilesApachemaven 4.编辑环境变量Path,追加%MAVEN_HOME…...

R语言医学数据分析实践-R语言的数据结构

【图书推荐】《R语言医学数据分析实践》-CSDN博客 《R语言医学数据分析实践 李丹 宋立桓 蔡伟祺 清华大学出版社9787302673484》【摘要 书评 试读】- 京东图书 (jd.com) R语言编程_夏天又到了的博客-CSDN博客 在R语言中,数据结构是非常关键的部分,它提…...

PID算法

PID算法是闭环控制中的核心算法之一,它结合了比例(P)、积分(I)和微分(D)三种控制策略,能够实现对被控对象的精确控制。以下将详细介绍PID算法,并针对P、I、D分别举出三个…...

C++day2

1.利用函数重载&#xff0c;实现对整形数组的冒泡排序&#xff0c;对浮点型数组的冒泡排序 #include <iostream>using namespace std;int bubblesort(int a[]) {int i,j,temp;for(i1;i<5;i){for(j0;j<5-i;j){if(a[j]>a[j1]){temp a[j];a[j] a[j1];a[j1] tem…...

RFdiffusion ContigMap类初始化方法解读

功能概述 __init__ 方法是 ContigMap 类的初始化函数,其核心任务是构建和管理一个蛋白质序列和结构的映射系统,处理用户提供的输入数据(如片段信息、参考序列、掩码等),并生成内部所需的各种索引和映射,以便在蛋白质设计中有效地定义、解析和操作不同区域的结构和序列。…...

LeetCode 每日一题 2024/12/2-2024/12/8

记录了初步解题思路 以及本地实现代码&#xff1b;并不一定为最优 也希望大家能一起探讨 一起进步 目录 12/2 52. N 皇后 II12/3 3274. 检查棋盘方格颜色是否相同12/4 2056. 棋盘上有效移动组合的数目12/5 3001. 捕获黑皇后需要的最少移动次数12/6 999. 可以被一步捕获的棋子数…...

5G模组AT命令脚本-关闭模组的IP过滤功能

关闭模组的IP过滤功能 关闭模组的IP过滤功能 5G 模组通常使用nat方式为 下挂设备或上位机提供上网服务&#xff0c;默认情况&#xff0c;不做NAt的包无法经由 模组转发&#xff0c;如果禁掉这个限制 &#xff0c;可使用本文中的配置命令本脚本用于关闭模组的IP过滤功能&#xf…...

得力DL-720C(new)标签热敏打印机

特点 适配标签宽度20-90mm的热敏标签纸&#xff0c;无需碳带。不适用于使用碳带上色的热转印纸&#xff08;如铜版纸&#xff09;。标签纸类型支持&#xff1a; 间隙纸&#xff08;靠间隙定位&#xff09;。得力自配的纸就是间隙纸&#xff0c;不透明。黑标纸&#xff08;靠背…...

openjdk17 jvm加载class文件,解析字段和方法,C++源码展示

##构造方法ClassFileParser&#xff0c;parse_stream解析文件流 ClassFileParser::ClassFileParser(ClassFileStream* stream,Symbol* name,ClassLoaderData* loader_data,const ClassLoadInfo* cl_info,Publicity pub_level,TRAPS) :_stream(stream),_class_name(NULL),_load…...

基于 AutoFlow 快速搭建基于 TiDB 向量搜索的本地知识库问答机器人

导读 本文将详细介绍如何通过 PingCAP 开源项目 AutoFlow 实现快速搭建基于 TiDB 的本地知识库问答机器人。如果提前准备好 Docker、TiDB 环境&#xff0c;整个搭建过程估计在 10 分钟左右即可完成&#xff0c;无须开发任何代码。 文中使用一篇 TiDB 文档作为本地数据源作为示…...

Vue项目实战-新能源汽车可视化(二)(持续更新中)

一.项目代码 1.DataSceen <template><div id"app-content"><div class"containerBox"><!-- 左边区域 --><div classleft><!-- 车辆情况 --><div class"item"></div><!-- 历史数据 -->&…...

CSS border 0.5px 虚线

border 0.5px 存在很多兼容问题&#xff0c;很多设备都会默认展示 1px 如果是实线可以用 background 和 height 1px 然后transform scaleY(0.5) 去实现。 但是虚线怎么办呢。 .ticket-line::before {content: ;position: absolute;top: 0;left: 0;right: 0;bottom: 0;width: …...

利用最大流算法解决Adam教授的双路径问题

利用最大流算法解决Adam教授的双路径问题 Adam教授的烦恼问题描述与转换转换步骤伪代码C代码示例解释Adam教授的烦恼 Adam教授有两个儿子,可不幸的是,他们互相讨厌对方。随着时间的推移,问题变得如此严重,他们之间不仅不愿意一起走到学校,而且每个人都拒绝走另一个人当天…...

c#如何开发后端

1选择开发框架 在 C# 中&#xff0c;用于后端开发最常用的框架是ASP.NET。它提供了构建 Web 应用程序、Web API 和微服务等多种后端服务所需的功能。ASP.NET有不同的模式&#xff0c;如ASP.NET MVC&#xff08;Model - View - Controller&#xff09;和ASP.NET Web API。ASP.NE…...

05_掌握Python3.11新特性-模式匹配

学习完本篇内容,你将掌握以下技能: 了解 Python 3.11 中的模式匹配新特性掌握如何使用模式匹配来简化代码和提高代码的可读性熟练掌握并应用到实际编程中python3.11新特性-模式匹配 在 Python 3.11 中,引入了模式匹配(pattern match...

【AI日记】24.12.09 kaggle 比赛 Titanic-12

【AI论文解读】【AI知识点】【AI小项目】【AI战略思考】【AI日记】 工作 内容&#xff1a; 学习 kaggle 入门比赛 Titanic - Machine Learning from Disaster学习机器学习&#xff08;pandas&#xff0c;numpy&#xff0c;sklearn&#xff09;&#xff0c;数据可视化&#xff…...

Linux,如何要定位并删除占用磁盘空间的大文件?

Linux&#xff0c;如何要定位并删除占用磁盘空间的大文件&#xff1f; 要定位并删除占用磁盘空间的大文件主要有以下这些步骤&#xff1a; 1. 使用 du 命令查找大文件或目录 du&#xff08;Disk Usage&#xff09;命令可以帮助你查找占用空间较大的文件或目录。 du -ah --…...

【Java】—— 图书管理系统

基于往期学习的类和对象、继承、多态、抽象类和接口来完成一个控制台版本的 “图书管理系统” 在控制台界面中实现用户与程序交互 任务目标&#xff1a; 1、系统中能够表示多本图书的信息 2、提供两种用户&#xff08;普通用户&#xff0c;管理员&#xff09; 3、普通用户…...

初识Linux · 线程同步

目录 前言&#xff1a; 认识条件变量 认识接口 快速使用接口 生产消费模型 前言&#xff1a; 前文我们介绍了线程互斥&#xff0c;线程互斥是为了防止多个线程对临界资源访问的时候出现了对一个变量同时操作的情况&#xff0c;对于线程互斥来说&#xff0c;我们使用到了锁…...

游戏引擎学习第40天

仓库 : https://gitee.com/mrxiao_com/2d_game 整理了一些需要完成的任务&#xff0c;确保所有内容都已清理完成&#xff0c;因为需要为后续的数学部分打好基础。下一步将认真开始处理数学相关内容&#xff0c;因此在此之前&#xff0c;需要彻底梳理未完成的事项&#xff0c;清…...

概率论——假设检验

解题步骤&#xff1a; 1、提出假设H0和H1 2、定类型&#xff0c;摆公式 3、计算统计量和拒绝域 4、定论、总结 Z检验 条件&#xff1a; 对μ进行检验&#xff0c;并且总体方差已知道 例题&#xff1a; 1、假设H0为可以认为是570N&#xff0c;H1为不可以认为是570N 2、Z…...

【Pandas】pandas isnull

Pandas2.2 General Top-level missing data 方法描述isna(obj)用于检测数据中的缺失值isnull(obj)用于检测数据中的缺失值notna(obj)用于检测数据中的非缺失值notnull(obj)用于检测数据中的非缺失值 pandas.isnull() pandas.isnull() 是 Pandas 库中的一个函数&#xff0c;…...

Rust HashMap使用

Rust 的 HashMap 是一个功能强大的数据结构&#xff0c;它结合了哈希表的高效性和 Rust 编程语言的内存安全特性。通过提供常数时间复杂度的查找、插入和删除操作&#xff0c;以及丰富的 API&#xff0c;它在许多实际应用中都非常有用。 示例代码&#xff1a; use std::colle…...

Spring Boot如何实现防盗链

一、什么是盗链 盗链是个什么操作&#xff0c;看一下百度给出的解释&#xff1a;盗链是指服务提供商自己不提供服务的内容&#xff0c;通过技术手段绕过其它有利益的最终用户界面&#xff08;如广告&#xff09;&#xff0c;直接在自己的网站上向最终用户提供其它服务提供商的…...

TIM输入捕获---STM

一、简介 IC输入捕获 输入捕获模式下&#xff0c;当通道输入引脚出现指定电平跳变时&#xff0c;当前CNT的值将被锁存在CCR中&#xff0c;可用于测量PWM波形的频率、占空比、脉冲间隔、电平持续时间等参数 每个高级定时器和通用定时器都拥有4个输入捕获通道 可配置为PWMI模…...

核密度估计——从直方图到核密度(核函数)估计_带宽选择

参考 核密度估计&#xff08;KDE&#xff09;原理及实现-CSDN博客 机器学习算法&#xff08;二十一&#xff09;&#xff1a;核密度估计 Kernel Density Estimation(KDE)_算法_意念回复-GitCode 开源社区 引言 在统计学中&#xff0c;概率密度估计是一种重要的方法&#xff0…...

javaScript Tips

一键去掉鼠标的图标 document.body.style.cursor none; 获取一个随机颜色 const randomHex () >#${Math.floor(Math.random() * 0xffffff).toString(16).padEnd(6, 0)}; 生成随机字符串&#xff0c;各种随机基本都是这个原理 const randomString () > Math.rand…...

【Ubuntu】清理、压缩VirtualBox磁盘空间大小

1、说明 本人为虚拟机创建了两个硬盘:root.vdi 和 hoom.vdi,在创建虚拟机时,分别挂载在/root目录和/home目录下。 下面演示分别清理、压缩两个磁盘的空间。 2、清理空间 1)清理 root.vid sudo dd if=/dev/zero of=/EMPTY bs=1M;sudo rm -f /EMPTY输出信息中会提示,如…...

若依 ruoyi VUE el-select 直接获取 选择option 的 label和value

1、最新在研究若依这个项目&#xff0c;我使用的是前后端分离的方案&#xff0c;RuoYi-Vue-fast(后端) RuoYi-Vue-->ruoyi-ui(前端)。RuoYi-Vue-fast是单应用版本没有区分那么多的modules 自己开发起来很方便&#xff0c;这个项目运行起来很方便&#xff0c;但是需要自定义的…...

C++小小复习一下

类&#xff0c;对象&#xff0c;成员变量&#xff0c;成员函数 特点&#xff1a;面向对象程序设计---因为要创建对象来调用类里面的函数或者成员变量 比如你的对象是一个生物-人&#xff1a;他会有自己的一些属性&#xff1a;身高&#xff0c;体重&#xff0c;性别等&#xf…...

JavaWeb学习(4)(四大域、HttpSession原理(面试)、SessionAPI、Session实现验证码功能)

目录 一、web四大域。 &#xff08;1&#xff09;基本介绍。 &#xff08;2&#xff09;RequestScope。(请求域) &#xff08;3&#xff09;SessionScope。(会话域) &#xff08;4&#xff09;ApplicationScope。(应用域) &#xff08;5&#xff09;PageScope。(页面域) 二、Ht…...

quartz 架构详解

‌Quartz是一个开源的作业调度框架&#xff0c;完全由Java编写&#xff0c;主要用于定时任务的调度和管理。Quartz的架构主要包括以下几个核心组件‌&#xff1a; 1.‌调度器&#xff08;Scheduler&#xff09;‌&#xff1a;调度器是Quartz的核心组件&#xff0c;负责管理Qua…...

Redis安装和Python练习(Windows11 + Python3.X + Pycharm社区版)

环境 Windows11 Python3.X Pycharm社区版 思路 1 github下载redis压缩包 &#xff0c;安装并启动redis服务&#xff0c;在Pycharm中运行python程序&#xff0c;连接redis服务&#xff0c;熟悉redis的使用和巩固python语言。 2 python开发环境的搭建参考 https://mp.csdn.…...

明年 iPhone 将搭载苹果自研 5G 基带芯片

明年 iPhone 将搭载苹果自研 5G 基带芯片 据彭博社记者 Mark Gurman 透露&#xff0c;苹果首款自主研发 5G 基带芯片即将面世。 苹果首款自研 5G 基带芯片将命名为「Sinope」&#xff0c;将应用在 2025 年发布的 iPhone SE、iPhone 17 Slim 版以及低端系列的 iPad 系列。「Si…...

1.1 Beginner Level学习之“编写简单的发布服务器和订阅服务器”(第十二节)

学习大纲&#xff1a; 1. 编写发布服务器节点 在ROS中&#xff0c;**节点&#xff08;Node&#xff09;**是与ROS网络通信的基本单位。在这个部分&#xff0c;我们将创建一个简单的发布节点&#xff08;talker&#xff09;&#xff0c;它会不断向话题&#xff08;topic&#x…...

C语言 字符串操作函数

strncpy() 用于将一个字符串的一部分拷贝到另一个字符串中。 char* strncpy(char* destination, const char* source, size_t num);参数&#xff1a;destination 是目标字符串的指针&#xff0c;表示将要拷贝到的位置source 是源字符串的指针&#xff0c;表示要拷贝的字符串num…...

论文概览 |《Cities》2024.07 Vol.150(上)

本次给大家整理的是《Cities》杂志2024年07月第150期的论文的题目和摘要&#xff0c;一共包括90篇SCI论文&#xff01;由于论文过多&#xff0c;我们将通过两篇文章进行介绍&#xff0c;本篇文章介绍第1--第45篇论文! 论文1 Spatiotemporal infection dynamics: Linking indiv…...

查看Windows系统上的Redis服务器是否设置了密码

查看 Redis 配置文件 1.找到 Redis 配置文件&#xff1a; 通常Redis配置文件名为 redis.windows.conf 或 redis.conf&#xff0c;它位于Redis安装目录中。 2.打开配置文件&#xff1a; 使用文本编辑器&#xff08;如Notepad、VS Code等&#xff09;打开该文件。 3.查找 re…...

30天学会Go--第6天 GO语言 RESTful API 学习与实践

30天学会Go–第6天 GO语言 RESTful API 学习与实践 文章目录 30天学会Go--第6天 GO语言 RESTful API 学习与实践一、 RESTful API 的设计原则1.1 RESTful API 的核心概念1.2 RESTful API 的 URL 设计1.3 RESTful API 的数据格式 二、 实现 RESTful API2.1 定义数据模型2.2 实现…...

数据分析特征标准化方法及其Python实现

数据分析特征标准化方法及其Python实现 1、概述 在数据分析中,对特征进行标准化主要是: 1、消除量纲影响 不同特征可能具有不同的量纲和数量级。 例如,一个特征可能是以米为单位的长度,而另一个特征可能是以秒为单位的时间。直接使用这些具有不同量纲的原始数据进行分析…...

【推导过程】常用共轭先验分布

文章目录 相关教程相关文献常用共轭先验分布预备知识贝叶斯统计后验分布的计算 正态均值(方差已知)的共轭先验分布是正态分布二项分布中的成功概率 θ 的共轭先验分布是贝塔分布正态均值(方差已知)的共轭先验分布是倒伽玛分布 作者&#xff1a;小猪快跑 基础数学&计算数学&…...

notepad++安装教程(超详细)

1.下载地址&#xff08;可以私信博主&#xff09; https://notepad-plus.en.softonic.com/download 2.解压安装...

Django快速入门

目录 1 创建django工程2 运行django3 Django工程目录详解4 开始一个app5 CBV和FBV6 使用模板7 使用模板语言8 自定义simple_tag Django 是用 Python 写的一个自由和开放源码 web 应用程序框架。 web框架是一套组件&#xff0c;能帮助你更快、更容易地开发web站点。当你开始构建…...