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

【JVM详解一】类加载过程与内存区域划分

一、简介

1.1 概述

JVM是Java Virtual Machine(Java虚拟机)的缩写,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。由一套字节码指令集、一组寄存器、一个栈、一个垃圾回收堆和一个存储方法域等组成。JVM屏蔽了与操作系统平台相关的信息,使得Java程序只需要生成在Java虚拟机上运行的目标代码(字节码),就可在多种平台上不加修改的运行,这也是Java能够“一次编译,到处运行的”原因。

所谓java能实现跨平台,是由在不同平台上运行不同的虚拟机决定的,因此java文件的执行不直接在操作系统上执行,而是通过jvm虚拟机执行,我们可以从这张图看到,JVM并没有直接与硬件打交道,而是与操作系统交互用以执行java程序。

1.2 JRE、JDK和JVM的关系

JRE(Java Runtime Environment, Java运行环境)是Java平台,所有的程序都要在JRE下才能够运行。包括JVM和Java核心类库和支持文件。

JDK(Java Development Kit,Java开发工具包)是用来编译、调试Java程序的开发工具包。包括Java工具(javac/java/jdb等)和Java基础的类库(java API )。

JVM(Java Virtual Machine, Java虚拟机)是JRE的一部分。JVM主要工作是解释自己的指令集(即字节码)并映射到本地的CPU指令集和OS的系统调用。Java语言是跨平台运行的,不同的操作系统会有不同的JVM映射规则,使之与操作系统无关,完成跨平台性。

使用JDK(调用JAVA API)开发JAVA程序后,通过JDK中的编译程序(javac)将Java程序编译为Java字节码,在JRE上运行这些字节码,JVM会解析并映射到真实操作系统的CPU指令集和OS的系统调用。

二、JVM架构

JVM的架构分为多个子系统,主要包括类加载子系统、运行时数据区、垃圾回收机制和执行引擎等。

2.1 类加载子系统

JVM 将 class 字节码文件加载到内存中, 并将这些静态数据转换成方法区中的运行时数据结构,在堆(并不一定在堆中,HotSpot在方法区中)中生成一个代表这个类的 java.lang.Class 对象,作为方法区类数据的访问入口。 

2.1.1 类加载器

把类加载阶段的 “ 通过一个类的全限定名来获取描述此类的二进制字节流 ” 这个动作交给虚拟机之外的类加载器来完成。这样的好处在于,我们可以自行实现类加载器来加载其他格式的类,只要是二进制字节流就行,这就大大增强了加载器灵活性。系统自带的类加载器分为三种:

  • 启动类加载器 ===》 Bootstrap ClassLoader
  • 扩展类加载器 ===》 Extension ClassLoader
  • 应用程序类加载器 ===》Application ClassLoader

2.1.1.1 双亲委派机制

如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父加载器去完成,每个层次的类加载器都是如此。因此所有的加载请求最终都会传送到Bootstrap类加载器(启动类加载器)中,只有父类加载反馈自己无法加载这个请求(它的搜索范围中没有找到所需的类)时,子加载器才会尝试自己去加载。

层级结构如下图所示:

双亲委派模型的优点:

java类随着它的加载器一起具备了一种带有优先级的层次关系。

例如类 java.lang.Object ,它存放在 rt.jar 之中,无论哪一个类加载器都要加载这个类,最终都是双亲委派模型最顶端的 Bootstrap 类加载器去加载。因此 Object 类在程序的各种类加载器环境中都是同一个类。相反,如果没有使用双亲委派模型,由各个类加载器自行去加载的话,如果用户编写了一个称为 “java.lang.Object” 的类,并存放在程序的ClassPath中,那系统中将会出现多个不同的 Object 类,java 类型体系中最基础的行为也就无法保证,应用程序也将会一片混乱。

2.1.1.2 自定义类加载器

继承 ClassLoader 类,重写 findClass() 方法:

2.1.2 类加载过程

类的加载过程如下:

 JVM类加载机制分为五个部分:加载,校验,准备,解析,初始化,下面我们就分别来看一下这五个过程。其中加载、校验、准备、初始化和卸载这个五个阶段的顺序是固定的,而解析则未必。为了支持动态绑定,解析这个过程可以发生在初始化阶段之后。

加载(Loading):类加载器从字节流中读取类的二进制数据并将其加载到内存中。
验证(Verification):验证类的字节码是否符合JVM规范,防止恶意代码的侵入。
准备(Preparation):为类的静态变量分配内存并设置默认值。
解析(Resolution):将类中的符号引用解析为直接引用。
初始化(Initialization):执行类的构造方法,初始化类的静态变量和静态代码块。

2.1.2.1 加载

类加载器从字节流中读取类的二进制数据并将其加载到内存中。

加载过程主要完成三件事情:

  • 通过类的全限定名来获取定义此类的二进制字节流
  • 将这个类字节流代表的静态存储结构转为方法区的运行时数据结构
  • 在堆中生成一个代表此类的 java.lang.Class 对象,作为访问方法区这些数据结构的入口。

这个过程主要由类加载器完成。

2.1.2.2 校验

验证类的字节码是否符合JVM规范,防止恶意代码的侵入。

  • 文件格式验证:基于字节流验证。
    • 是否以魔数0xCAFEBABE开头。
    • 主、次版本号是否在当前虚拟机处理范围之内。
    • 常量池的常量中是否有不被支持的常量类型(检查常量tag标志)。
    • 指向常量的各种索引值中是否有指向不存在的常量或不符合类型的常量。
    • CONSTANT_Utf8_info型的常量中是否有不符合UTF8编码的数据。
    • Class文件中各个部分及文件本身是否有被删除的或附加的其他信息。
  • 元数据验证:基于方法区的存储结构验证。
    • 这个类是否有父类(除了java.lang.Object之外,所有类都应当有父类)。
    • 这个类是否继承了不允许被继承的类(被final修饰的类)。
    • 如果这个类不是抽象类,是否实现了其父类或接口之中所要求实现的所有方法。
    • 类中的字段、方法是否与父类产生矛盾(例如覆盖了父类的final字段,或者出现不符合规则的方法重载,例如方法参数都一致,但返回值类型却不同等等)。
  • 字节码验证:基于方法区的存储结构验证。主要目的是通过数据流和控制流分析,确定程序语义是合法的、符合逻辑的。
    • 保证任意时刻操作数栈的数据类型与指令代码序列都能配合工作,例如不会出现类似这样的情况:在操作数栈放置了一个int类型的数据,使用时却按long类型来加载入本地变量表中。
    • 保证跳转指令不会跳转到方法体以外的字节码指令上。
    • 保证方法体中的类型转换是有效的,例如可以把一个子类对象赋值给父类数据类型,但是把父类对象赋值给子类数据类型,甚至把对象赋值给与它毫无继承关系、完全不相干的一个数据类型,则是危险不合法的。
  • 符号引用验证:基于方法区的存储结构验证。可以看作是类对自身以外(常量池中的各种符号引用)的信息进行匹配性校验。
    • 符号引用中通过字符串描述的全限定名是否能够找到对应的类。
    • 在指定类中是否存在符合方法的字段描述符以及简单名称所描述的方法和字段。
    • 符号引用中的类、字段、方法的访问性(private、protected、public、default)是否可被当前类访问。

2.1.2.3 准备

为类变量分配内存(不包括实例变量),并将其初始化为默认值。(此时为默认值,在初始化的时候才会给变量赋值)即在方法区中分配这些变量所使用的内存空间。例如:

此时在准备阶段过后的初始值为0而不是123;将value赋值为123的 putstatic 指令是程序被编译后,存放于类构造器<clinit>方法之中。
特例:

此时value的值在准备阶段过后就是123。

2.1.2.4 解析

把类型中的符号引用转换为直接引用。

  • 符号引用与虚拟机实现的布局无关,引用的目标并不一定要已经加载到内存中。各种虚拟机实现的内存布局可以各不相同,但是它们能接受的符号引用必须是一致的,因为符号引用的字面量形式明确定义在Java虚拟机规范的Class文件格式中。
  • 直接引用可以是指向目标的指针,相对偏移量或是一个能间接定位到目标的句柄。如果有了直接引用,那引用的目标必定已经在内存中存在

主要有以下四种:

  • 类或接口的解析
  • 字段解析
  • 类方法解析
  • 接口方法解析

2.1.2.5 初始化

初始化阶段是执行类构造器<clinit>方法的过程。<clinit>方法是由编译器自动收集类中的类变量的赋值操作和静态语句块中的语句合并而成的。虚拟机会保证<clinit>方法执行之前,父类的<clinit>方法已经执行完毕。如果一个类中没有对静态变量赋值也没有静态语句块,那么编译器可以不为这个类生成<clinit>方法。

java中,对于初始化阶段,有且只有以下五种情况才会对要求类立刻“初始化”(加载,验证,准备,自然需要在此之前开始):

  • 使用 new 关键字实例化对象、访问或者设置一个类的静态字段(被final修饰、编译器优化时已经放入常量池的例外)、调用类方法,都会初始化该静态字段或者静态方法所在的类。
  • 初始化类的时候,如果其父类没有被初始化过,则要先触发其父类初始化。
  • 使用 java.lang.reflect 包的方法进行反射调用的时候,如果类没有被初始化,则要先初始化。
  • 虚拟机启动时,用户会先初始化要执行的主类(含有main)。
  • jdk 1.7后,如果 java.lang.invoke.MethodHandle 的实例最后对应的解析结果是 REF_getStatic、REF_putStatic、REF_invokeStatic方法句柄,并且这个方法所在类没有初始化,则先初始化。

2.2 运行时数据区(HotSpot虚拟机)

JVM在程序执行时,管理着多个内存区域,称为运行时数据区。每个区域有不同的用途,主要包括以下几个区域:

  • 方法区:存储类的相关信息(类信息、常量、静态变量、方法数据等)。
  • 堆(Heap):存储Java对象,是垃圾回收器管理的区域。
  • 虚拟机栈(JVM Stack):每个线程都有一个栈,用来存储方法的局部变量、操作数栈、返回地址等信息。
  • 程序计数器(PC Register):存储当前线程正在执行的字节码的地址。
  • 本地方法栈(Native Method Stack):为JVM调用本地方法(如C/C++编写的库)提供支持。

2.2.1 程序计数器

线程私有;是一块较小的内存空间,可以看做是当前线程所执行的字节码的行号指示器,唯一不会造成 OutOfMemoryError 情况的区域。不过当线程执行的是 Native 方法的时候这个计数器中的值为 undefined 。

2.2.2 java虚拟机栈

线程私有;描述的是 java 方法执行的内存模型:每个方法在执行的同时都会创建一个栈帧,用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每个方法从调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程。栈帧指执行一个方法所使用的那部分栈,线程的所有方法的栈帧串起来就组成了一个完整的 java 虚拟机栈。java 虚拟机栈针对线程而言,线程里的方法对应栈中的元素----栈帧;每执行一个方法,就为这个方法创建对应的栈帧,并 push 到 线程这个大容器-----java虚拟机栈 中,执行完成就 pop 出栈。

局部变量表存放了编译期可知的各种基本数据类型(boolean、byte、char、short、int、long、float、double)、对象引用(用来指向内存中分配的类实例或者数组) 和 returnAddress 类型(指向字节码的指针)。注:long和double会占用2个局部变量空间(8字节),其余数据类型只占用一个(4字节)。对于局部变量,如果是基本类型,会把值直接存储在栈;如果是引用类型,比如String s = new String("william");会把其对象存储在堆,而把这个对象的引用(指针)存储在栈。

Java虚拟机规范中,对这个区域规定了两种异常状况:

  • 线程请求栈的深度大于虚拟机所允许栈的深度,将抛出Stack Overflow Error
  • 如果虚拟机栈可以动态扩展且扩展时无法申请到足够的内存,会抛出OutOfMemoryError

这里注意的是如果递归的方法递归的太深很容易抛出上面两种异常,所以递归虽然写起来方便,但是性能会有所下降,并且容易抛出异常。

-Xss128k:设置每个线程的堆栈大小为128k,若不设置则为JVM默认值,此时默认可动态扩展。在相同物理内存下,减小这个值能生成更多的线程。但是操作系统对一个进程内的线程数还是有限制的,不能无限生成,经验值在3000~5000左右。

2.2.3 本地方法栈

线程私有;作用和 java 虚拟机栈相似,区别是 java 虚拟机栈为虚拟机执行 java 方法(也就是字节码)服务,而本地方法栈则为虚拟机使用到的 Native 方法服务。Native方法指java调用非java代码(c++)的接口(jni)。

sayHello() 方法加了一个关键字 native ,就代表是一个native接口。执行这个方法时,会根据 jni.h来找到真正的C++编写的sayHello() 的实际函数。jni.h 是存在于 %JAVA_HOME%\include 下面的一个文件,另外还有个 %JAVA_HOME%\include\win32 下的jni_md.h。

2.2.4 java堆

线程共享;是java虚拟机所管理的内存中最大的一块,在虚拟机启动时创建,用于存放对象实例。java堆是垃圾收集器管理的主要区域。由于现在的垃圾回收算法多是分代收集,所以Java堆里面又可分为:新生代和老年代;再细致一点年轻代还能分为Eden区、From Survivor空间、To Survivor空间。并且根据Java虚拟机规范的规定:Java堆可以处于物理上不连续的内存空间中,只要逻辑上连续即可。注意:有实例没有被分配,且堆无法再扩展的时候会抛出OutOfMemoryError异常,虚拟机调优其实也主要关注的是这个区域。成员变量作为对象的属性,当然是放在堆里了。对象在堆里,对象中的内容就是各种字段。

  • -Xms:初始堆大小(最小堆)。
  • -Xmx:最大堆大小。

-Xms 和 -Xmx 设置成一致的值可以避免堆自动扩展。Oracle官方推荐堆的初始化大小与堆可设置的最大值一般是相等的,即 Xms = Xmx,因为起始堆内存太小(Xms),会导致启动初期频繁 GC,起始堆内存较大(Xmx)有助于减少 GC 次数

  • -Xmn:年轻代大小(Sun官方推荐配置为整个堆的1/3)。对 -XX:newSize、-XX:MaxnewSize两个参数的同时配置。

JVM内存大小 = 年轻代大小 + 老年代大小 + 永久代大小(perm)。永久代一般固定大小为64m,所以增大年轻代后,将会减小年老代大小。此值对系统性能影响较大,Sun官方推荐配置为整个堆的3/8。

  • -XX:NewSize :指定新生代初始大小。
  • -XX:MaxNewSize :指定新生代最大大小。
  • -XX:NewRatio :是年老代 新生代相对的比例,比如NewRatio=2,表明年老代是新生代的2倍。老年代占了heap的2/3,新生代占了1/3。
  • -XX:SurvivorRatio :配置的是在新生代里面Eden和一个Survivor比例。-XX:SurvivorRatio=8表示新生代的Eden占8/10,S1和S2各占1/10.

2.2.5 方法区

线程共享;方法区是JVM的一种规范,方法区在jdk1.7的实现是永久代,jdk1.8的实现是元空间Metaspace。可以选择不实现垃圾收集。方法区主要用于存储类字节码、静态变量、常量池、即时编译器编译后的代码等数据。

对于方法区的理解我们要注意以下几个方面:

  • 方法区(Method Area)与堆一样,是各个线程共享的内存区域。
  • 方法区在JVM启动的时候被创建,并且它实际的物理内存空间和虚拟机堆区一样都可以是不连续的。
  • 方法区在JVM启动的时候被创建,并且它实际的物理内存空间和虚拟机堆区一样都可以是不连续的。
  • 方法区的大小跟堆空间一样,可以选择固定大小或者可扩展。方法区的大小决定了系统可以保存多少个类。如果系统定义了太多的类,导致方法区溢出,虚拟机同样会抛出内存溢出错误,如java.lang.OutOfMemoryError:PermGen space或者java.lang.OutOfMemoryError:Metaspace。

以下情况都可能导致方法区发生OOM异常:加载大量的第三方jar包、Tomcat部署的工程过多(30~50个)或者大量动态地生成反射类。

JVM常量池(详细见下一章):

  • class文件常量池:诞生于编译时,存在于class文件中,存放符号引用和字面量。
  • 运行时常量池:诞生于JVM运行时,jdk1.7永久代被移除后存在于元空间,存放class文件元信息描述、引用类型数据、编译后的代码数据、类文件常量池(综合了每个class文件常量池)
  • 字符串常量池:jdk1.6处于永久代,jdk1.7后处于堆区;存放字符串对象的引用
  • 基本类型包装类常量池:位于堆区
2.2.5.1 永久代

存储已被 java 虚拟机加载的类字节码、静态变量、常量池、即时编译器编译后的代码等数据。jdk1.7 的 HotSpot 虚拟机中,已经把原本放在永久代的 字符串常量池 和 静态变量 转移到 java 堆;符号引用(Symbols) 转移到了本地内存(Native Memory)。jdk1.8中,原有的永久代改为了元空间(Metaspace),直接使用机器物理内存,因为原来的永久代内存大小不易评估,同时调优效率较低。永久代的垃圾收集是和老年代捆绑在一起的。

配置参数:

-XX:PermSize=300M 设置永久代大小

-XX:MaxPermSize=300M 设置永久代最大大小

2.2.5.2 元空间(Metaspace)
存储类的元信息;存储位置不在虚拟机中,而是使用本地内存
-XX:MetaspaceSize ,初始空间大小,达到该值就会触发垃圾收集进行类型卸载,同时GC会对该值进行调整:如果释放了大量的空间,就适当降低该值;如果释放了很少的空间,那么在不超过MaxMetaspaceSize时,适当提高该值。
-XX:MaxMetaspaceSize ,最大空间,默认是没有限制的。
  除了上面两个指定大小的选项以外,还有两个与 GC 相关的属性:
-XX:MinMetaspaceFreeRatio ,在GC之后,最小的Metaspace剩余空间容量的百分比,减少为分配空间所导致的垃圾收集。
-XX:MaxMetaspaceFreeRatio ,在GC之后,最大的Metaspace剩余空间容量的百分比,减少为释放空间所导致的垃圾收集。
永久代和元空间的区别
1) 存储位置不同:永久代物理上是堆的一部分,和老年代、新生代地址在逻辑上是连续的;元空间属于本地内存。
2) 存储内容不同:元空间存储类的元信息,静态变量和字符串常量池等并入堆中;相当于永久代的数据被分裂到了堆和元空间。
JDK 8 中永久代向元空间的转换原因
  • 1、字符串存在永久代中,容易出现性能问题和内存溢出。
  • 2、类及方法的信息等比较难确定其大小,因此对于永久代的大小指定比较困难,太小容易出现永久代溢出,太大则容易导致老年代溢出。而对于元空间来说类的元数据可以在本地内存(native memory)分配,所以其最大可利用空间是整个系统内存的可用空间。
  • 永久代会为 GC 带来不必要的复杂度,并且回收效率偏低。
  • Oracle 可能会将HotSpot 与 JRockit 合二为一。

相关文章:

【JVM详解一】类加载过程与内存区域划分

一、简介 1.1 概述 JVM是Java Virtual Machine&#xff08;Java虚拟机&#xff09;的缩写&#xff0c;是通过在实际的计算机上仿真模拟各种计算机功能来实现的。由一套字节码指令集、一组寄存器、一个栈、一个垃圾回收堆和一个存储方法域等组成。JVM屏蔽了与操作系统平台相关…...

250207-MacOS修改Ollama模型下载及运行的路径

在 macOS 上&#xff0c;Ollama 默认将模型存储在 ~/.ollama/models 目录。如果您希望更改模型的存储路径&#xff0c;可以通过设置环境变量 OLLAMA_MODELS 来实现。具体步骤如下&#xff1a; 选择新的模型存储目录&#xff1a;首先&#xff0c;确定您希望存储模型的目标目录路…...

Win10 部署llama Factory 推荐教程和遇到的问题

教程 【大模型微调】使用Llama Factory实现中文llama3微调_哔哩哔哩_bilibili 大模型微调&#xff01;手把手带你用LLaMA-Factory工具微调Qwen大模型&#xff01;有手就行&#xff0c;零代码微调任意大语言模型_哔哩哔哩_bilibili 遇到问题解决办法 pytorch gpu国内镜像下载…...

如何在Android Studio中开发一个简单的Android应用?

Android Studio是开发Android应用的官方集成开发环境&#xff08;IDE&#xff09;&#xff0c;它提供了许多强大的功能&#xff0c;使得开发者能够高效地创建Android应用。如果你是Android开发的初学者&#xff0c;本文将引导你如何在Android Studio中开发一个简单的Android应用…...

ubuntu下迁移docker文件夹

在 Ubuntu 系统中迁移 Docker 文件夹&#xff08;如 Docker 数据存储文件夹 /var/lib/docker&#xff09;到另一个磁盘或目录&#xff0c;通常是为了释放系统盘空间。以下是迁移过程的详细步骤&#xff1a; 1. 停止 Docker 服务 在进行迁移之前&#xff0c;必须停止 Docker 服…...

嵌入式面试题 C/C++常见面试题整理_7

一.什么函数不能声明为虚函数? 常见的不能声明为虚函数的有:普通函数(非成员函数):静态成员函数;内联成员函数;构造函数;友元函数。 1.为什么C不支持普通函数为虚函数?普通函数(非成员函数)只能被overload&#xff0c;不能被override&#xff0c;声明为虚函数也没有什么意思…...

使用OBS推流,大华摄像头 srs服务器播放

说明&#xff1a; ffmpeg可以推流&#xff0c;但是是命令行方式不太友好&#xff0c;还可以使用主流的OBS开源推流软件&#xff0c;可从官网Open Broadcaster Software | OBS 下载最新版本&#xff0c;目前很多网络主播都是用它做直播。该软件支持本地视频文件以及摄像头推流。…...

CSS 组合选择符详解与实战示例

在 Web 开发过程中&#xff0c;CSS 用于定义页面元素的样式&#xff0c;而选择器则帮助我们精确定位需要添加样式的元素。今天我们主要来讲解 CSS 中的组合选择符&#xff0c;它们能够根据 DOM 结构中元素之间的关系来选中目标元素&#xff0c;从而写出结构清晰、易于维护的 CS…...

Window系统通过Docker本地安装ollama和deepseek

在 Windows 系统上安装 Ollama 和 DeepSeek 的步骤如下&#xff1a; 安装 Ollama 安装 WSL&#xff08;Windows Subsystem for Linux&#xff09;&#xff1a; 如果还没有安装 过WSL的&#xff08;安装过的你直接跳过就行了&#xff09;&#xff0c;可以按照以下步骤进行安装&…...

镜头放大倍率和像素之间的关系

相互独立的特性 镜头放大倍率&#xff1a;主要取决于镜头的光学设计和结构&#xff0c;决定了镜头对物体成像时的缩放程度&#xff0c;与镜头的焦距等因素密切相关。比如&#xff0c;微距镜头具有较高的放大倍率&#xff0c;能将微小物体如昆虫、花朵细节等放大成像&#xff0…...

P3413 SAC#1 - 萌数

题目背景 本题由世界上最蒟蒻的 SOL 提供。 寂月城网站是完美信息教室的官网。地址:http://191.101.11.174/mgzd。 题目描述 蒟蒻 SOL 居然觉得数很萌! 好在在他眼里,并不是所有数都是萌的。只有满足“存在长度至少为 22 的回文子串”的数是萌的——也就是说,101 是萌…...

[RabbitMQ] RabbitMQ常见面试题

&#x1f338;个人主页:https://blog.csdn.net/2301_80050796?spm1000.2115.3001.5343 &#x1f3f5;️热门专栏: &#x1f9ca; Java基本语法(97平均质量分)https://blog.csdn.net/2301_80050796/category_12615970.html?spm1001.2014.3001.5482 &#x1f355; Collection与…...

Java运行时数据区

JVM主要流程包括三部分&#xff1a; 首先是 ClassLoard 类加载器&#xff0c;加载数据源文件到jvm当中然后将加载好的数据存放在运行时数据区最后由引擎进行解释和编译的工作 1.Java 内存区域&#xff1a; 1.1 程序计数器 程序计数器&#xff08;Program Counter Register&a…...

【03】 区块链分布式网络

3-1 P2P网络 传统中心化网络由中央服务器保存全量数据。客户端之间无法直接连接&#xff0c;必须通过中央服务器作为桥梁。客户端必须和中央服务器建立连接后访问资源。客户端之间并无连通。 在P2P网络中通过将数据资源分散在网络各个节点中存储以及节点间交互连接&#xff0…...

【SQL server】关于SQL server彻底的卸载删除。

1.未彻底卸载删除SQL Server会出现的问题 如果没有彻底删除之前的SQL server&#xff0c;就可能会出现这个 当要安装新的实例的时候因为之前安装过sql server没有删除干净而导致下图问题&#xff0c;说实例名已经存在。 2.首先要先关闭服务 “开始R”可以快速进入运行&#…...

【含文档+PPT+源码】基于微信小程序的校园志愿者管理系统的设计与实现

项目介绍 本课程演示的是一款 基于微信小程序的校园志愿者管理系统的设计与实现&#xff0c;主要针对计算机相关专业的正在做毕设的学生与需要项目实战练习的 Java 学习者。 1.包含&#xff1a;项目源码、项目文档、数据库脚本、软件工具等所有资料 2.带你从零开始部署运行本…...

Docker入门(Windows)

视频链接&#xff1a;Docker | 狂神说 环境说明 Windows For Docker WSL2 概念 Docker是什么&#xff1f; 百度百科&#xff1a;百度百科 Docker 是一个开源的平台&#xff0c;它利用操作系统级虚拟化技术来打包和运行应用程序。通过使用容器化技术&#xff0c;Docker 提…...

深度求索(DeepSeek)的AI革命:NLP、CV与智能应用的技术跃迁

Deepseek官网&#xff1a;DeepSeek 引言&#xff1a;AI技术浪潮中的深度求索 近年来&#xff0c;人工智能技术以指数级速度重塑全球产业格局。在这场技术革命中&#xff0c;深度求索&#xff08;DeepSeek&#xff09;凭借其前沿的算法研究、高效的工程化能力以及对垂直场景的…...

Mac本地体验LM studio

博主很懒&#xff0c;不爱打字&#xff01; 1、LM studio官网&#xff1a;LM Studio - Discover, download, and run local LLMs 2、下载DMG文件&#xff0c;安装 3、使用vscode工具&#xff0c;commandshiftH【全局替换功能】&#xff0c;选择目录/Applications/LM\ Studio…...

Spring Boot 线程池自定义拒绝策略:解决任务堆积与丢失问题

如何通过自定义线程池提升系统稳定性 背景 在高并发系统中&#xff0c;线程池管理至关重要。默认线程池可能导致&#xff1a; 资源浪费&#xff08;创建过多线程导致 OOM&#xff09;任务堆积&#xff08;队列满后任务被拒绝&#xff09;任务丢失&#xff08;默认拒绝策略丢…...

(二)TensorRT-LLM | 模型导出(v0.20.0rc3)

0. 概述 上一节 对安装和使用有个基本介绍。根据这个 issue 的描述&#xff0c;后续 TensorRT-LLM 团队可能更专注于更新和维护 pytorch backend。但 tensorrt backend 作为先前一直开发的工作&#xff0c;其中包含了大量可以学习的地方。本文主要看看它导出模型的部分&#x…...

连锁超市冷库节能解决方案:如何实现超市降本增效

在连锁超市冷库运营中&#xff0c;高能耗、设备损耗快、人工管理低效等问题长期困扰企业。御控冷库节能解决方案通过智能控制化霜、按需化霜、实时监控、故障诊断、自动预警、远程控制开关六大核心技术&#xff0c;实现年省电费15%-60%&#xff0c;且不改动原有装备、安装快捷、…...

多模态商品数据接口:融合图像、语音与文字的下一代商品详情体验

一、多模态商品数据接口的技术架构 &#xff08;一&#xff09;多模态数据融合引擎 跨模态语义对齐 通过Transformer架构实现图像、语音、文字的语义关联。例如&#xff0c;当用户上传一张“蓝色连衣裙”的图片时&#xff0c;接口可自动提取图像中的颜色&#xff08;RGB值&…...

Java多线程实现之Callable接口深度解析

Java多线程实现之Callable接口深度解析 一、Callable接口概述1.1 接口定义1.2 与Runnable接口的对比1.3 Future接口与FutureTask类 二、Callable接口的基本使用方法2.1 传统方式实现Callable接口2.2 使用Lambda表达式简化Callable实现2.3 使用FutureTask类执行Callable任务 三、…...

Java-41 深入浅出 Spring - 声明式事务的支持 事务配置 XML模式 XML+注解模式

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; &#x1f680; AI篇持续更新中&#xff01;&#xff08;长期更新&#xff09; 目前2025年06月05日更新到&#xff1a; AI炼丹日志-28 - Aud…...

[Java恶补day16] 238.除自身以外数组的乘积

给你一个整数数组 nums&#xff0c;返回 数组 answer &#xff0c;其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法&#xff0c;且在 O(n) 时间复杂度…...

A2A JS SDK 完整教程:快速入门指南

目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库&#xff…...

音视频——I2S 协议详解

I2S 协议详解 I2S (Inter-IC Sound) 协议是一种串行总线协议&#xff0c;专门用于在数字音频设备之间传输数字音频数据。它由飞利浦&#xff08;Philips&#xff09;公司开发&#xff0c;以其简单、高效和广泛的兼容性而闻名。 1. 信号线 I2S 协议通常使用三根或四根信号线&a…...

Caliper 配置文件解析:fisco-bcos.json

config.yaml 文件 config.yaml 是 Caliper 的主配置文件,通常包含以下内容: test:name: fisco-bcos-test # 测试名称description: Performance test of FISCO-BCOS # 测试描述workers:type: local # 工作进程类型number: 5 # 工作进程数量monitor:type: - docker- pro…...

为什么要创建 Vue 实例

核心原因:Vue 需要一个「控制中心」来驱动整个应用 你可以把 Vue 实例想象成你应用的**「大脑」或「引擎」。它负责协调模板、数据、逻辑和行为,将它们变成一个活的、可交互的应用**。没有这个实例,你的代码只是一堆静态的 HTML、JavaScript 变量和函数,无法「活」起来。 …...