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

JVM 机制

目录

一、什么是 JVM:

二、JVM 的运行流程:

三、JVM 内存区域划分:

1、( 1 )  程序计数器:

1、( 2 )  元数据区:

1、( 3 )  栈:

1、( 4 )  堆:

四、类加载:

1、什么时候会触发类加载:

2、类加载过程:

2、( 1 )  加载:

2、( 2 )  验证:

2、( 3 )  准备:

2、( 4 )  解析:

2、( 5 )  初始化:

五、双亲委派模型:

六、垃圾回收机制:

1、判断 “垃圾” 的方式:

1、( 1 )  引用计数:

1、( 2 )  可达性分析:

2、如何回收 “ 垃圾 ” :

2、( 1 )  标记 - 清除算法:

2、( 2 )  复制算法:

2、( 3 )  标记 - 整理算法:

2、( 4 )  分代回收(综合方案):


一、什么是 JVM:

        “JVM ”全称 java 虚拟机 ,它提供了 java 代码程序运行的环境,有一个很重要的特性就是 “一次编写,到处运行” ,意思是,一段相同的 java 代码,不需要修改代码相关逻辑就可以跨平台运行。

        JVM 更准确的说,是 java 语言的“ 运行时环境” ,为什么这么说?因为 JVM 就是把 java 源代码,翻译成 cpu 能够识别的机器指令。而其他的一些编程语言(比如C++),源代码编译出来的就已经是标准的 cpu 能够执行的指令了,但这也给这些语言(比如C++)带来了一些问题,就是代码不能够跨平台。

        我们所说的跨平台,指的是同一个代码程序,可以直接放在不同的操作系统或者不同架构的 cpu 上运行。而类似 C++ 这些编程语言,不同的操作系统或者不同架构的 cpu,需要针对不同的平台单独编译生成对应的机器指令,因为不同的操作系统,提供的 api 是不同的;不同架构的 cpu,指令集是不兼容的。这些情况导致 C++ 编程语言同一段源代码无法跨平台运行。

二、JVM 的运行流程:

         java 这种编程语言,因为有 JVM 的存在,可以实现跨平台运行,大致流程:

        首先,开发人员编写的 java 代码文件( .java ),通过编译器(javac)转换成字节码文件( .class ),JVM 读取字节码文件,转换成机器指令(二进制指令)由 cpu 执行

        在此过程中,可以看到,JVM 相当于充当一个 “翻译官” 的作用,JVM 里有多个不同系统 api ,不同架构的 cpu 框架指令集,根据具体底层的平台,同一段java源代码可以翻译出对应的机器指令,使其得以运行。

        到这里,可以体现出来,java 代码虽然多了一次翻译,运行效率比C++低了,但是换来的是可以跨平台,这大大提高了开发效率,是值得的。

        

        

        

三、JVM 内存区域划分:

        java 程序跑起来,得到了 java 进程,这就需要从操作系统申请内存来运行进程了,为了提高 java 进程的运行效率和安全性,JVM 把这些内存区域划分为 程序计数器 ,元数据区 ,栈 ,堆 。

1、( 1 )  程序计数器:

         在操作系统中,线程是 cpu 的调度的基本执行单位;进程是系统资源分配的基本单位。而 程序计数器(分配给的内存空间比较小,仅用于存储当前线程正在执行的字节码指令地址),每个线程都会有一个

        在单核 cpu 的环境下,Thread创建的线程是并发执行的,也就是一个线程执行一段时间后,又切换到另一个线程执行,通过不断的切换,让我们感觉是 “同时进行”的。那么, 当切换回来的的线程,怎么知道这个执行线程上一次执行到哪个位置了?还有就是当遇到循环了,怎么程序怎么回到循环起始的位置?

        每段代码都有对应的字节码地址,上面我们说到,每个线程独立拥有一个程序计数器,程序计数器的一个作用就是记录当前线程正在执行的字节码指令地址。相当于 “保存上下文位置” 。 另一个作用就是跳转运行的指令地址,也就是当程序执行遇到 if ,while ,for ,方法调用,异常处理等这些情况,不再是默认的顺序执行了,而是跳转到对应的指令地址继续执行

        综上所述程序计数器记录的就是“程序下一步执行的位置”。

1、( 2 )  元数据区:

        元数据区主要的作用是存储类的结构信息和类的静态具体内容(静态变量、静态常量(final),静态方法、静态代码块类的结构信息比如继承关系(这个类继承了哪个类),实现的接口(这个类实现的接口),类的属性(属性的名字,类型......),类实现的方法(方法名字,参数列表,返回值...)。

        这里的信息和内容要注意理解,内容是整个,信息是描述。

1、( 3 )  栈:

         栈这个内存区域保存了方法的调用关系,这里的栈类似于“数据结构的栈”,也就是元素先进后出的特性。且每个线程都会有一个独立的栈

        

        在 jvm 中所说的栈,把这里栈每个元素称为 “栈帧” ,每个栈帧表示一次方法调用,比如最底下的A栈帧调用了栈帧B,也就是我们常说的方法A里面调用了方法B,每个栈帧包含的数据有方法的参数,方法的局部变量,方法执行结束后要返回的结果,方法结束后要跳转回的地址。

        当栈帧执行完(方法结束 / return)了,对应的栈帧就会销毁。所以,当我们写出死递归的代码的时候,就会出现栈溢出的情况,就是栈帧满了。

1、( 4 )  堆:

       通过 new 关键字创建出来的对象就在堆里。包含了其对象的实例,成员属性及其对应的值。

        一张图理解对应关系:

        

总结(整体占内存空间大小关系 ):       

四、类加载:

        类加载,就是把字节码文件(最初存放在硬盘的 .class 文件)加载到内存中变成能使用的 Class 对象类

        但是,不是程序开始运行就加载全部的 .class ,而是要用上了对应的类,才会开始加载。且一个类只会加载一次,下面具体分析。

1、什么时候会触发类加载:

当:

        构造某个类的实例。

        调用类的静态方法(类似比如 main)或静态成员变量。

        当创建子类的实例时,如果父类尚未被加载,则会先触发父类的加载。

2、类加载过程:

类加载分为五个时机,下面具体分析:

2、( 1 )  加载:

        根据代码中编写的 “全限定类名” ,找到对应的 .class 文件(找的过程也叫“双亲委派模型”)。这里的全限定类名,就是包名 + 类名,比如我的代码中有个类是 Test,这个类在 Demo 包里,那么全限定类名是Demo.Test 。

        再打开文件,把读取的 .class(二进制数据)解析成对应的类的具体内容到内存中。由于 .class 二进制数据是严格按照规范排列的,包含多个部分,每个部分对应着类的具体内容(类的名字,类的字段,类继承的哪个类,实现的接口......),jvm会按顺序解析其中的每个部分,并将其转换成内存的类结构。

// 伪代码:解析类结构
class ClassFile {int magic;                 // 魔数(前 4 字节是0xCAFEBABE)int version;               // 版本号(决定了 JVM 能否处理该文件)ConstantPool constantPool; // 常量池(存储类中使用的所有常量,包括类名、方法名、字段名等。)int accessFlags;           // 访问标志(如public、final)int thisClass;             // 类索引int superClass;            // 父类索引// ... 字段、方法、属性表 ...
}

        这里的魔数,指的是二进制文件的前四个字节,这四个字节作是标识当前的二进制文件是什么后缀的(常见的有.exe / .png / .class / .mp4 / .mp3/......)。

2、( 2 )  验证:

        上述的 .class 文件解析完后,再去验证是否合法如果在验证的过程中,发现某个格式存在问题(魔数错误,jvm版本不兼容......),就会抛出异常,并提醒告知开发人员。

2、( 3 )  准备:

         验证完后,就可以给类对象结构信息和类中静态成员变量分配空间,并把静态成员变量初始化为 0 (放在元数据区)。此处申请的内存空间,是一个 “未初始化” 的内存空间(内存上每个字节都是 “0”)。

2、( 4 )  解析:

        准备完之后,将代码中的 “名字”(符号引用)翻译成 “内存地址”(直接引用),也就是对代码中的常量进行赋值,放到内存中。

2、( 5 )  初始化:

        解析完之后,就进入真正开始执行类中编写的 java 程序代码,将主导权交给应用程序,负责执行静态代码块,将静态成员变量初始化实际值(赋值)。

        如果当前的类继承的父类 / 接口还没有被加载,会重复这五个步骤初始化父类 / 接口。

五、双亲委派模型:

        上面类加载讲到,双亲委派模型在第一个阶段(加载)的时候出现,即根据类的全限定类名找到对应的 .class 文件的过程。

        JVM 中进行类加载的时候,需要依赖内部的模块,即 “类加载器” 。而 JVM 中自带了三种类加载器。        

        以上的三个类加载器之间,存在逻辑上的 “ 父子关系 ” ,而不是真正意义上的父子 / 继承关系,注意区别。

三个加载器之间有这么一个关系:

绿色代表他们的关系,从上到下可以把他们看作 “爷爷” ,“爸爸” ,“儿子” 。

        当一个类要加载的时候,首先进入 “儿子 ”这个加载器,加载器会自身检查这个类有没有加载过,如果这个类已经被加载过了,直接返回如果这个类还没有被加载,则 “ 儿子” 这个加载器会委托给 “父亲” 这个加载器,再检查,再委托“爷爷” 这个加载器,后面再自上往下搜索对应目录库尝试加载。(结合上图理解)

        值得注意的是,java 自带的类(比如String这个类,他所在的包名是 java.lang,全限定类名是java.lang.String)是在“爷爷” 这个加载器完成的;而我们自己写的类,一般是在 “儿子” 这个加载器完成的。

六、垃圾回收机制:

        垃圾回收(gc)是一种自动内存管理机制,其核心作用是自动识别并回收不再使用的对象所占用的内存空间。要注意的是,触发 gc 的时候,JVM 会暂停所有线程的执行,仅让 GC 线程运行,可以类似理解为其他线程为 gc 这个线程让步而停止工作。、

        那么 gc 回收的内存区域主要是哪里?主要是回收 这个内存区域,因为堆是保存对象实例的区域,当一个对象之后的代码不再涉及了,就会被回收,并且是以对象为维度的回收。

        那么,上诉的对象被判定为 “垃圾” ,通俗来说是之后的代码不再涉及了,更准确的说应该是对象是否可达性(判断是否有引用指向这个对象)。下面讲述两种方式。但 java 只涉及一种方式。

1、判断 “垃圾” 的方式:

1、( 1 )  引用计数:

        先说明,这个方式 java 并没有采用,但是其他的计算机语言(python...)涉及到。主要理解其中的设计思想。

        这个引用计数的方式,就是给每个对象实例包含一个计数器(需要占用内存),当有新引用指向这个对象时,计数器 +1 ,引用失效(把当前引用置为 null )计数器 -1,当计数器为 0 时,对象就立即被回收。

        上述的方式,会存在两个问题,第一个问题就是计数器本身占用内存空间,当如果创建的对象很小的时候,计数器会占用其相当一部分空间。第二个问题就是,会出现循环引用的问题。

class Test {Test t;
}Test a = new Test( );
Test b = new Test( );a.t = b;
b.t = a;a = null;
b= null;

        比如上面的这段代码,当创建出来的的两个实例,每个实例都有对应的计数器 ,栈上也保存了分别指向他们的引用,计数器当前都是 1 ,执行当执行 a.t = b 和 b.t = a 后,两个实例中的 t 字段也分别保存了对方的引用,此时双方的计数器都变成了 2 ,当执行 a = null 和 b = null ,此时栈区指向他们的引用都没了,此时双方的计数器都变成了 1。到这里,此时外部已经没有可以使用的引用执行双方了,此时应该被销毁才对,但是销毁不了,因为计数器还是 1 。

        上图可以看到,双方的对象实例里有指向对方的引用,但是使用不了。此时就是构成了循环引用问题。

1、( 2 )  可达性分析:

这种方案,就是 java 使用的方案 。

        这种方案的核心思想是,通过确立根对象作为起点,遍历所有的引用访问对应的对象,访问到的对象被标记为 “存活” ,未被访问到对象被视为 “垃圾” 。

        上述的根对象,可以是栈上的局部变量(引用类型);常量池里指向的对象(final 修饰的引用类型);元数据区(静态成员的引用类型)。 JVM 就会以他们作为根开始访问。

        举两个例子,比如这个代码:

class Test {Test t;
}Test a = new Test( );
Test b = new Test( );a.t = b;
b.t = a;a = null;
b= null;

        之前我们讲到,这个代码使用引用计数的方式会出现循环引用的问题。但是,在可达性分析的方法里,尽管两个对象有字段互相引用对方的实例,但是由于他们栈中的 a 和 b 引用(作为根)变量断开。此时这两个实例就访问不到,就会被回收。

        另一个例子,类似于二叉树,根节点作为根对象,当某一个节点被置为 null 了,那么即使通过根节点依次遍历,这个节点的所有子节点都无法被访问到,就会被回收。

2、如何回收 “ 垃圾 ” :

通过上面的可达性分析识别出垃圾后,就可以进行回收操作了,有下面四种回收垃圾算法

2、( 1 )  标记 - 清除算法:

        标记,也就是上面的可达性分析找到 “ 垃圾 ” 的过程,清除,也就是直接释放这部分“垃圾”的内存空间。但是,这种方式会存在 内存碎片 的问题。

        上图中,每个方块代表 1MB 的内存空间,红色代表被释放的内存空间,而白色的代表还正在使用的内存空间,此时,当我们想要申请 2 MB 的内存就会申请失败,因为申请内存时都是需要一段连续的内存空间的。

2、( 2 )  复制算法:

        这个方式,将内存区域划分为两个大小相等区域,首先,使用的时候,一边是正在使用的内存,另一边的内存是空闲的,通过一次 gc 后,正在使用的内存的存活的对象会被全部复制到另一边空闲的内存而这一边就全部释放。

        这种方式,很好的解决了内存碎片的问题,但是,有两个很大的弊端,那就是可使用的内存只有一半,并且如果存活的对象比较多 / 比较大,复制的开销是很大的。

2、( 3 )  标记 - 整理算法:

        当标记出 “垃圾” 后,通过类似于顺序表删除元素的操作把后面存活的对象,往前搬到前面释放出来的空间(往前靠)

        这种方式,可以解决内存碎片的问题,也可以避免复制算法带来内存浪费,但是,这种方式也存在一个明显的弊端,那就是移动对象需额外计算位置的开销。

2、( 4 )  分代回收(综合方案):

这个方案,是把前面的几个方案,扬长避短,综合起来的方案。

        这个方案的核心思想,是把内存区域划分为新生代老年代,这两个区域的 gc 频率是不一样的,新生代区域的频率较高老年代的 gc 频率较低

        当一些对象刚开始创建出来,存放在伊甸区,通过一次 gc 后,通过复制算法,存活的对象进入其中一个幸存区。原来的伊甸区清空。

        期间可能有新创建的对象进入了伊甸区,后面继续 gc ,再通过复制算法,伊甸区存活的对象和幸存区存活的对象进入另一个幸存区原来的幸存区和伊甸区清空。

         当 gc 到一定程度后(15次 gc )依旧存活的对象,通过复制算法,进入老年代区,此时老年代区的对象经过这么多次 gc 都依旧存活,我们就认为其生命周期以后大概率也会很长,所以 gc 的频率变低。或者如果创建的这个对象很大,就不太适合复制算法了,直接进入老年代区。

        其中,新生代区采用的是复制算法老年代区采用的是标记 - 清理 标记 - 整理算法

相关文章:

JVM 机制

目录 一、什么是 JVM: 二、JVM 的运行流程: 三、JVM 内存区域划分: 1、( 1 ) 程序计数器: 1、( 2 ) 元数据区: 1、( 3 ) 栈: 1、( 4 ) 堆: 四、类加载: 1、什么时候会触…...

Java泛型详解

文章目录 1. 引言1.1 什么是泛型1.2 为什么需要泛型1.3 泛型的优势2. 泛型基础2.1 泛型类多个类型参数2.2 泛型方法2.3 泛型接口2.4 类型参数命名约定3. 类型擦除3.1 什么是类型擦除3.2 类型擦除的影响1. 无法获取泛型类型参数的实际类型2. 无法创建泛型类型的数组3. 无法使用`…...

机器学习,深度学习,神经网络,深度神经网络之间有何区别?

先说个人观点:机器学习>神经网络>深度学习≈深度神经网络。深度学习是基于深度神经网络的,深度神经网络和浅层神经网络都是神经网络,而机器学习是包括神经网络在内的算法。 一、机器学习 先说涵盖范围最广的机器学习。机器学习&#…...

AtomicInteger

AtomicInteger 是 Java 并发包 (java.util.concurrent.atomic) 中的一个原子类,用于在多线程环境下对整数进行原子操作。 核心特性 原子性 提供线程安全的原子操作(如自增、加法、比较并交换等),确保在多线程环境中操作不会被中…...

威布尔比例风险模型(Weibull Proportional Hazards Model, WPHM)详解:原理、应用与实施

威布尔比例风险模型(Weibull Proportional Hazards Model, WPHM)详解:原理、应用与实施 一、核心原理:从威布尔分布到比例风险模型 1. 威布尔分布的数学本质 威布尔分布通过两个关键参数(形状参数 (k) 和尺度参数 (\…...

Dubbo:Docker部署Zookeeper、Dubbo Admin的详细教程和SpringBoot整合Dubbo的实战与演练

🪁🍁 希望本文能给您带来帮助,如果有任何问题,欢迎批评指正!🐅🐾🍁🐥 文章目录 一、背景二、Dubbo概述三、Dubbo与SpringCloud的关系四、Dubbo技术架构五、Docker安装Zoo…...

Windows 上安装下载并配置 Apache Maven

1. 下载 Maven 访问官网: 打开 Apache Maven 下载页面。 选择版本: 下载最新的 Binary zip archive(例如 apache-maven-3.9.9-bin.zip)。 注意:不要下载 -src 版本(那是源码包)。 2. 解压 Mave…...

Unbuntu 命令

Ubuntu 命令速查表​ ​分类​​命令​​功能描述​​示例/常用选项​​​​文件与目录​ls列出目录内容ls -a(显示隐藏文件); ls -lh(详细列表易读大小) cd切换目录cd ~(主目录); cd ..(上级…...

机器学习-人与机器生数据的区分模型测试-数据处理1

附件为训练数据,总体的流程可以作为参考。 导入依赖 import pandas as pd import os import numpy as np from sklearn.model_selection import train_test_split,GridSearchCV from sklearn.ensemble import RandomForestClassifier,VotingClassifier from skle…...

【Linux】进程间通信(一):认识管道

📝前言: 这篇文章我们来讲讲进程间通信——认识管道 🎬个人简介:努力学习ing 📋个人专栏:Linux 🎀CSDN主页 愚润求学 🌄其他专栏:C学习笔记,C语言入门基础&a…...

AMD Vivado™ 设计套件生成加密比特流和加密密钥

概括 重要提示:有关使用AMD Vivado™ Design Suite 2016.4 及更早版本进行 eFUSE 编程的重要更新,请参阅AMD设计咨询 68832 。 本应用说明介绍了使用AMD Vivado™ 设计套件生成加密比特流和加密密钥(高级加密标准伽罗瓦/计数器模式 (AES-GCM)…...

第三十四节:特征检测与描述-SIFT/SURF 特征 (专利算法)

一、特征检测:计算机视觉的基石 在计算机视觉领域中,特征检测与描述是实现图像理解的核心技术。就像人类通过识别物体边缘、角点等特征来认知世界,算法通过检测图像中的关键特征点来实现: 图像匹配与拼接 物体识别与跟踪 三维重建 运动分析 其中,SIFT(Scale-Invariant F…...

【AI】SpringAI 第二弹:基于多模型实现流式输出

目录 一、基于多模型实现流式输出 1.1 什么是流式输出 1.2 多模型引入 1.3 代码实现 1.3.1 流式输出的API介绍 1.3.2 Flux 源码分析 二、了解 Reactor 模型 三、SSE 协议 一、基于多模型实现流式输出 1.1 什么是流式输出 流式输出(Streaming Output)是指数据在生成过程…...

SQL语句执行问题

执行顺序 select [all|distinct] <目标列的表达式1> AS [别名], <目标列的表达式2> AS [别名]... from <表名1或视图名1> [别名],<表名2或视图名2> [别名]... [where <条件表达式>] [group by <列名>] [having <条件表达式>] [ord…...

模型量化AWQ和GPTQ哪种效果好?

环境&#xff1a; AWQ GPTQ 问题描述&#xff1a; 模型量化AWQ和GPTQ哪种效果好? 解决方案&#xff1a; 关于AWQ&#xff08;Adaptive Weight Quantization&#xff09;和GPTQ&#xff08;Generative Pre-trained Transformer Quantization&#xff09;这两种量化方法的…...

Github 2025-05-17 Rust开源项目日报 Top10

根据Github Trendings的统计,今日(2025-05-17统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量Rust项目10Dart项目1RustDesk: 用Rust编写的开源远程桌面软件 创建周期:1218 天开发语言:Rust, Dart协议类型:GNU Affero General Public Li…...

借助 CodeBuddy 打造我的图标预览平台 —— IconWiz 开发实录

我正在参加CodeBuddy「首席试玩官」内容创作大赛&#xff0c;本文所使用的 CodeBuddy 免费下载链接&#xff1a;腾讯云代码助手 CodeBuddy - AI 时代的智能编程伙伴 想做一款自己的图标预览平台 这段时间我在做前端 UI 设计时&#xff0c;常常需要到处找图标素材&#xff0c;复…...

KL散度 (Kullback-Leibler Divergence)

KL散度&#xff0c;也称为相对熵 (Relative Entropy)&#xff0c;是信息论中一个核心概念&#xff0c;用于衡量两个概率分布之间的差异。给定两个概率分布 P ( x ) P(x) P(x) 和 Q ( x ) Q(x) Q(x)&#xff08;对于离散随机变量&#xff09;或 p ( x ) p(x) p(x) 和 q ( x …...

【Linux网络】NAT和代理服务

NAT 之前我们讨论了&#xff0c;IPv4协议中&#xff0c;IP地址数量不充足的问题。 原始报文途径路由器WAN口时&#xff0c;对报文中的源IP进行替换的过程&#xff0c;叫做NAT。 NAT技术当前解决IP地址不够用的主要手段&#xff0c;是路由器的一个重要功能&#xff1a; NAT能…...

DeepSeek赋能电商,智能客服机器人破解大型活动人力困境

1. DeepSeek 与电商客服结合的背景 1.1 电商行业客服需求特点 电商行业具有独特的客服需求特点&#xff0c;这些特点决定了智能客服机器人在该行业的必要性和重要性。 高并发性&#xff1a;电商平台的用户数量庞大&#xff0c;尤其是在促销活动期间&#xff0c;用户咨询量会…...

Unity序列化字段、单例模式(Singleton Pattern)

一、序列化字段 在Unity中&#xff0c;序列化字段是一个非常重要的概念&#xff0c;主要用于在Unity编辑器中显示和编辑类的成员变量&#xff0c;或者在运行时将对象的状态保存到文件或网络中。 1.Unity序列化字段的作用 在编辑器中显示和编辑字段&#xff1a;默认情况下&…...

一个可拖拉实现列表排序的WPF开源控件

从零学习构建一个完整的系统 推荐一个可通过拖拉&#xff0c;来实现列表元素的排序的WPF控件。 项目简介 gong-wpf-dragdrop是一个开源的.NET项目&#xff0c;用于在WPF应用程序中实现拖放功能&#xff0c;可以让开发人员快速、简单的实现拖放的操作功能。 可以在同一控件内…...

hadoop.proxyuser.代理用户.授信域 用来干什么的

在Hadoop的core-site.xml文件中存在三个可选配置&#xff0c;如下 <property><name>hadoop.proxyuser.root.hosts</name><value>*</value> </property> <property><name>hadoop.proxyuser.root.groups</name><value…...

python 自动化教程

文章目录 前言整数变量​字符串变量​列表变量​算术操作​比较操作​逻辑操作​if语句​for循环遍历列表​while循环​定义函数​调用函数​导入模块​使用模块中的函数​启动Chrome浏览器​打开网页​定位元素并输入内容​提交表单​关闭浏览器​发送GET请求获取网页内容​使…...

C++学习:六个月从基础到就业——C++11/14:列表初始化

C学习&#xff1a;六个月从基础到就业——C11/14&#xff1a;列表初始化 本文是我C学习之旅系列的第四十三篇技术文章&#xff0c;也是第三阶段"现代C特性"的第五篇&#xff0c;主要介绍C11/14中的列表初始化特性。查看完整系列目录了解更多内容。 引言 在C11之前&a…...

城市静音革命:当垃圾桶遇上缓冲器

缓冲垃圾桶的核心原理是通过机械或液压装置实现垃圾桶盖的缓慢闭合&#xff0c;包含以下技术要点&#xff1a;‌能量吸收机制‌液压式&#xff1a;通过活塞挤压油液产生阻尼力&#xff0c;将动能转化为热能耗散弹簧式&#xff1a;利用弹性变形储存和释放能量&#xff0c;配合摩…...

数据库的规范化设计方法---3种范式

第一范式&#xff08;1NF&#xff09;&#xff1a;确保表中的每个字段都是不可分割的基本数据项。 第二范式&#xff08;2NF&#xff09;&#xff1a;在满足1NF的基础上&#xff0c;确保非主属性完全依赖于主键。 第三范式&#xff08;3NF&#xff09;&#xff1a;在满足2NF的基…...

p024基于Django的网上购物系统的设计与实现

开发语言&#xff1a;Python框架&#xff1a;djangoPython版本&#xff1a;python3.7.7数据库&#xff1a;mysql 5.7数据库工具&#xff1a;Navicat11开发软件&#xff1a;PyCharm 系统展示 管理员登录 管理员功能界面 用户管理 商品类型管理 商品信息管理 系统管理 订单管理…...

C++跨平台开发:挑战与应对策略

C跨平台开发&#xff1a;挑战与应对策略 在如今设备多样、操作系统碎片化的开发环境中&#xff0c;跨平台能力已成为衡量软件生命力与团队工程效率的重要指标。C 作为高性能系统级语言&#xff0c;在游戏引擎、嵌入式系统、实时渲染等领域依旧坚挺。然而&#xff0c;实现“一次…...

Kotlin 作用域函数(let、run、with、apply、also)对比

Kotlin 的 作用域函数&#xff08;Scope Functions&#xff09; 是简化代码逻辑的重要工具&#xff0c;它们通过临时作用域为对象提供更简洁的操作方式。以下是 let、run、with、apply、also 的对比分析&#xff1a; 一、核心区别对比表 函数上下文对象引用返回值是否扩展函数…...

JavaScript性能优化实战(11):前沿技术在性能优化中的应用

引言 随着Web应用复杂度和性能需求不断提高,传统的JavaScript优化技术已经无法满足某些高性能计算场景的需求。本文将深入探讨前沿Web技术如何突破JavaScript的性能瓶颈,为Web应用提供接近原生应用的性能体验。从底层计算到图形渲染,从并发处理到动画优化,我们将通过实际案…...

数据结构【AVL树】

AVL树 1.AVL树1.AVL的概念2.平衡因子 2.AVl树的实现2.1AVL树的结构2.2AVL树的插入2.3 旋转2.3.1 旋转的原则 1.AVL树 1.AVL的概念 AVL树可以是一个空树。 它的左右子树都是AVL树&#xff0c;且左右子树的高度差的绝对值不超过1。AVL树是一颗高度平衡搜索二叉树&#xff0c;通…...

电动调节V型球阀:行业应用与材质选择全解析

电动调节V型球阀&#xff1a;行业应用与材质选择全解析 作为工业自动化控制中的关键设备&#xff0c;电动调节V型球阀凭借其独特的结构设计与高性能调节能力&#xff0c;在石油、化工、造纸等高要求领域广泛应用。本文将从核心功能、行业应用场景、材质选择要点等方面深入解析…...

页面上如何显示特殊字符、Unicode字符?

在前端开发中&#xff0c;显示特殊字符通常涉及到HTML实体&#xff08;HTML Entities&#xff09;或 Unicode 字符的使用。以下是一些常见的方法来处理特殊字符的显示&#xff1a; 1、HTML实体&#xff1a; HTML为一些常见的特殊字符提供了预定义的实体。例如&#xff0c;要显…...

桌面端进程通信

以下是关于 Electron 桌面端进程通信的基本知识点总结: 一、Electron 进程模型基础 1. 进程类型与职责 进程类型职责权限主进程(Main)创建窗口、系统级操作、IPC中枢完全Node.js访问权限渲染进程(Renderer)展示Web内容、UI交互默认受限(可配置开启Node.js)预加载脚本(Prelo…...

vue2 切换主题色以及单页面好使方法

今天要新增一个页面要根据不同公司切换不同页面主题色&#xff0c;一点一点来&#xff0c;怎么快速更改 el-pagination 分页组件主题色。 <el-pagination :page-size"pageSize" :pager-count"pageCount"layout"sizes, prev, pager, next, jumper,…...

三层固定实体架构:高效实现图上的检索增强生成(RAG)

知识图谱正在成为跨各个领域组织和检索信息的强大工具。它们越来越多地与机器学习和自然语言处理技术相结合,以增强信息检索和推理能力。在本文中,我介绍了一种用于构建知识图谱的三层架构,结合了固定本体实体、文档片段和提取的命名实体。通过利用嵌入和余弦相似度,这种方…...

pnpm 与 npm 的核心区别

以下是 pnpm 与 npm 的核心区别总结&#xff0c;涵盖依赖管理、性能、安全性等关键维度&#xff1a; 1. 依赖存储机制 • npm&#xff1a; 每个项目的依赖独立存储于 node_modules&#xff0c;即使多个项目使用相同版本的包&#xff0c;也会重复下载和存储。例如&#xff0c;1…...

NVMe简介6之PCIe事务层

PCIe的事务层连接了PCIe设备核心与PCIe链路&#xff0c;这里主要基于PCIe事务层进行分析。事务层采用TLP传输事务&#xff0c;完整的TLP由TLPPrefix、TLP头、Payload和TLP Digest组成。TLP头是TLP中最关键的部分&#xff0c;一般由三个或四个双字的长度&#xff0c;其格式定义如…...

【C++详解】string各种接口如何使用保姆级攻略

文章目录 一、string介绍二、string使用构造函数析构函数赋值运算符重载string的遍历修改方法1、下标[]2、迭代器3、范围for 迭代器使用详解const迭代器反向迭代器&#xff08;reverse) Capacity(容量相关)size/lengthmax_sizecapacityclear/emptyshrink_to_fit(缩容)reserve(扩…...

深入理解 requestIdleCallback:浏览器空闲时段的性能优化利器

requestIdleCallback 核心作用 requestIdleCallback 是浏览器提供的 API&#xff0c;用于将非关键任务延迟到浏览器空闲时段执行&#xff0c;避免阻塞用户交互、动画等关键任务&#xff0c;从而提升页面性能体验。 基本语法 const handle window.requestIdleCallback(callb…...

QML鼠标事件和按键事件

1 鼠标事件 1.1 MouseArea组件 在QML中&#xff0c;鼠标事件主要通过MouseArea元素处理&#xff0c;它是用于检测和响应鼠标交互的核心组件。常用属性 cursorShape: 光标形状acceptedButtons: 设置响应鼠标的哪些按键事件&#xff0c;默认为鼠标左键 Qt.LeftButton&#xff1…...

Animaster:一次由 CodeBuddy 主导的 CSS 动画编辑器诞生记

我正在参加CodeBuddy「首席试玩官」内容创作大赛&#xff0c;本文所使用的 CodeBuddy 免费下载链接&#xff1a;腾讯云代码助手 CodeBuddy - AI 时代的智能编程伙伴 起心动念&#xff1a;我想要一个动画编辑器 那天我突然想到&#xff0c;如果能有一个简单好用的 CSS 动画编辑…...

Git 版本控制系统入门指南

Git 版本控制系统入门指南 一、Git 基础概念 1. 什么是 Git&#xff1f; Git 是一个分布式版本控制系统&#xff0c;它可以&#xff1a; 跟踪文件变化协调多人协作管理代码版本支持离线工作保证数据完整性 2. Git 的特点 分布式架构快速分支操作完整历史记录数据完整性保…...

GitHub 趋势日报 (2025年05月16日)

本日报由 TrendForge 系统生成 https://trendforge.devlive.org/ &#x1f310; 本日报中的项目描述已自动翻译为中文 &#x1f4c8; 今日整体趋势 Top 10 排名项目名称项目描述今日获星总星数语言1TapXWorld/ChinaTextbookPDF教材。⭐ 4792⭐ 19814Roff2xming521/WeClone&…...

C/C++之内存管理

1. 内存分布 我们定义的变量对于电脑来说也叫数据&#xff0c;同时电脑也会把这些数据分为不同的类型&#xff0c;分别是局部数据&#xff0c;静态数据&#xff0c;全局数据&#xff0c;常量数据和动态申请数据。 在 C 中&#xff0c;各类数据存储位置如下&#xff1a; • 局…...

GitHub文档加载器设计与实现

文章结构&#xff1a; 目录 GitHub文档加载器设计与实现 引言 架构设计 主要组件 核心功能 文档加载流程 加载单个文件 加载目录内容 错误处理与健壮性 分支回退策略 文件类型和大小限制 安全性考虑 SSL证书验证 使用示例 基本使用 测试环境配置 最佳实践 结…...

历史数据分析——中证白酒

简介 中证白酒指数选取涉及白酒生产业务相关上市公司证券作为指数样本,为投资者提供更多样化的投资标的。 估值 中证白酒总体的PB是5.26,在过去十年间位于23.76%,属于较低的水平。 中证白酒总体的PE是20.13,在过去十年间,位于14.24%,属于较低的水平。 从估值的角度似…...

PHP8.0版本导出excel失败

环境&#xff1a;fastadmin框架&#xff0c;不是原版接手的项目。PHP8.0,mysql5.7. code // 创建一个新的 Spreadsheet 对象 $spreadsheet new Spreadsheet(); $worksheet $spreadsheet->getActiveSheet();// 设置表头 $worksheet->setCellValue(A1, ID); $worksheet…...

Seata源码—5.全局事务的创建与返回处理二

大纲 1.Seata开启分布式事务的流程总结 2.Seata生成全局事务ID的雪花算法源码 3.生成xid以及对全局事务会话进行持久化的源码 4.全局事务会话数据持久化的实现源码 5.Seata Server创建全局事务与返回xid的源码 6.Client获取Server的响应与处理的源码 7.Seata与Dubbo整合…...