JVM ②-双亲委派模型 || 垃圾回收GC

这里是Themberfue 

  •  在上节课对内存区域划分以及类加载的过程有了简单的了解后,我们再了解其他两个较为重要的机制,这些都是面试中常考的知识点,有必要的话建议背出来,当然不是死记硬背,而是要有理解的背~~~
  • 如果对 JVM 的其他机制感兴趣的话,建议去阅读一些书籍,我的建议是失眠的时候看看,可以有效改善睡眠(bushi

类加载器 

  • 类加载器从 JDK 1.0 就出现了,最初只是为了满足 Java Applet(已经被淘汰) 的需要。后来,慢慢成为 Java 程序中的一个重要组成部分,赋予了 Java 类可以被动态加载到 JVM 中并执行的能力。
  • 我们先看官方 API 文档的介绍:A class loader is an object that is responsible for loading classes. The class ClassLoader is an abstract class. Given the binary name of a class, a class loader should attempt to locate or generate data that constitutes a definition for the class. A typical strategy is to transform the name into a file name and then read a "class file" of that name from a file system. Every Class object contains a reference to the ClassLoader that defined it. Class objects for array classes are not created by class loaders, but are created automatically as required by the Java runtime. The class loader for an array class, as returned by Class.getClassLoader() is the same as the class loader for its element type; if the element type is a primitive type, then the array class has no class loader.
  • 简单来说:
  • 在 Java 中,类加载器(ClassLoader)是负责加载类文件(.class 文件)的组件。类加载器的主要作用是将字节码加载到 JVM 中,并使其成为JVM 可识别并执行的类
  • 类加载器是Java 运行时环境的一部分它控制了类的加载过程,并且是 JVM 的重要组成部分之一。类加载器是一个负责加载类的对象,用于实现类加载过程中的加载这一步。
  • 每个类都是通过 类加载器加载的。类加载器将字节码文件加载到内存,并将其转化为 JVM 内部的 Class 对象,从而使得程序能够使用该类。
  • 每个 Java 类都有一个引用指向加载它的 ClassLoader
  • 数组类不是通过 ClassLoader 创建的(数组类没有对应的二进制字节流),是由 JVM 直接生成的。
    class Class<T> {...private final ClassLoader classLoader;@CallerSensitivepublic ClassLoader getClassLoader() {//...}...
    }

  • 在前边多线程的学习中,我们学习了懒汉模式,Java 类加载的规则也是采用懒汉模式来加载类的。
  • JVM 启动时,并不会一次性加载所有类,而是根据需要动态加载类。也就是说,大部分类在具体用到的时候才会去加载,这样对内存更加友好。这便是懒汉模式一个应用~~~
  • 对于已经加载的类会被放在 ClassLoader 中。在类加载的时候,系统会首先判断当前类是否被加载过。已经被加载的类会直接返回,否则才会尝试加载。也就是说,对于一个类加载器来说,相同二进制名称的类只会被加载一次。
    public abstract class ClassLoader {...private final ClassLoader parent;// 由这个类加载器加载的类。private final Vector<Class<?>> classes = new Vector<>();// 由VM调用,用此类加载器记录每个已加载类。void addClass(Class<?> c) {classes.addElement(c);}...
    }

分类

Bootstrap ClassLoader(引导类加载器)

  • 作用:负责加载 JDK 核心类库,也就是 Java标准库(如 java.lang.*java.util.* 等)。
  • 加载路径:它从 JRE 的 lib 目录下加载类,如 rt.jarresources.jar 等。
  • 特点:Bootstrap 类加载器是 JVM 自带的,用 C++ 实现,不能被 Java 代码继承。它加载的类在 JVM 启动时就被加载到内存。

Extension ClassLoader(扩展类加载器)

  • 作用:负责加载 JDK 扩展类库,即 JRE/lib/ext/ 目录下的类,或者 java.ext.dirs 指定的路径中的类。
  • 加载路径:默认加载路径是 JRE/lib/ext/ 目录下的 JAR 文件和类文件。
  • 特点Extension ClassLoader 是由 ClassLoader 继承而来,用 Java 实现。

Application ClassLoader(应用类加载器)

  • 作用:负责加载 应用程序的类库,即 classpath 下的类。
  • 加载路径:从 classpath 环境变量指定的路径加载类文件(例如:.class 文件或 .jar 包)。
  • 特点:是最常见的类加载器,它负责加载我们自己编写的 Java 类文件,通常由 java.lang.ClassLoader 类提供。Java 的第三方库,例如使用 Maven 管理的库

自定义类加载器(Custom ClassLoader)

  • 作用:开发者可以继承 ClassLoader 类,重新实现 findClass() 方法,来创建自己特定的类加载器。
  • 用途:自定义类加载器通常用于 插件化、动态加载、热部署 等场景。

类加载器的父子关系

  • Java 中的类加载器是按照父子层级结构组织的。每个类加载器都有一个父类加载器,类加载的过程遵循 父加载器优先加载的原则。
  • 类加载器的父子关系如下:
    • Bootstrap ClassLoader 是根加载器,它不继承任何类加载器。
    • Extension ClassLoaderBootstrap ClassLoader 的子类。
    • Application ClassLoaderExtension ClassLoader 的子类。

双亲委派模型

  • Java 的类加载机制采用了 双亲委派模型。该模型的核心思想是:每个类加载器都会首先委托给父类加载器进行加载,只有父类加载器无法加载时,子类加载器才会尝试加载。
  • 流程:当一个类加载器需要加载一个类时,它会 首先委托给父加载器。如果父加载器不能加载该类(即类不存在),子加载器才会 自己尝试加载该类。如果子加载器依然不能加载该类,则 返回错误
  • 简单来说就是:在进行类加载时,也就是通过全限定类名找 .class 文件时,会先从 Application ClassLoader 作为入口开始,随后把 加载类 这样的任务委托给其父类,也就是 Extension ClassLoader 来进行。Extension ClassLoader 也不会立刻开始 加载类 的任务,而是继续委托给其父类,也就是 Bootstrap ClassLoader 来进行。Bootstrap Loader 作为顶层类加载器,自然没有父类了,便会从 Bootstrap Loader 这一层开始查找,也就是先从 Java标准库 开始查找。如果 Bootstrap Loader 没有找到,则交给其子类 Extension ClassLoader 查找,若 Extension ClassLoader 没有找到,则交给其子类 Application ClassLoader 查找,若依旧没有找到且没有子类时,则抛出异常

  • ⚠️双亲委派模型并不是一种强制性的约束,只是 JDK 官方推荐的一种方式。
  • 其实这个双亲翻译的容易让别人误解,我们一般理解的双亲都是父母,这里的双亲更多地表达的是“父母这一辈”的人而已,并不是说真的有一个 MotherClassLoader 和一个FatherClassLoader 。个人觉得翻译成单亲委派模型更好一些,不过,国内既然翻译成了双亲委派模型并流传了,按照这个来也没问题,不要被误解了就好。 
  • 双亲委派模型保证了 Java 程序的稳定运行,可以避免类的重复加载(JVM 区分不同类的方式不仅仅根据类名,相同的类文件被不同的类加载器加载产生的是两个不同的类),也保证了 Java 的核心 API(如 java.lang.String)不被篡改。

类加载器的应用

自定义类加载器

  • 在一些特殊的应用场景下,如 热部署、插件机制、动态代理 等,可以通过 自定义类加载器 来控制类的加载方式。例如,JSP 热部署、Spring 容器的 Bean 加载等,都需要自定义类加载器。

Java 的反射机制

  • 反射机制(如 Class.forName())通过类加载器动态加载类,并获取类的构造方法、字段、方法等信息,支持 运行时动态创建对象调用方法 等操作。

隔离加载

  • Java 类加载器的父子层次结构使得不同应用程序可以 隔离类的加载,避免不同程序之间的类冲突。例如,Tomcat、Jetty 等应用服务器支持 Web 应用程序的隔离,它们为每个应用创建不同的类加载器,防止不同应用之间共享类。

 垃圾回收(GC)

  • 在过去 C语言时,我们在申请了一块内存空间后,要去手动释放这块内存,也就是调用 free() 函数,若不释放掉,很容易造成内存泄漏和内存溢出等问题。就算代码块里确实调用了 free() 函数,有时候程序也可能因为 bug 没有走到那里,从而导致内存泄漏等。
  • 手动释放内存太麻烦了,所以 Java 为了开发的便捷性,便引入 GC(Garbage Collection,垃圾回收) 机制,JVM 会自动识别出哪块内存是不需要使用的,并释放掉这些内存,不再需要我们过度关注。
  • 相比较于 C++,Java 的代码执行时间要短一些,就是因为 JVM 的这些机制。不过,随着 JDK 版本的不断迭代,目前 Java 的执行时间以及和 C++ 较为接近了,STW 时间大部分情况下都在 1ms 以下。(STW,Stop The World,在 JVM GC 时,就会因为需要GC,其他业务的代码不得不停止运行,必须等待 GC 执行完后才能继续运行,这个时间间隔就被称为 STW

  • Java 的 GC 主要是针对对象内存的回收和对象内存的分配。所以,Java GC 最核心的功能是  内存中对象的分配与回收。 是 GC 主要管理的区域,所以 堆 也被称作 GC 堆(Garbage Collected Heap)。在 Java 代码执行的过程中,必然伴随着新对象的创建旧对象的消亡,所以,回收内存 的本质就是 回收对象
  • 在 Java 中,对象的生命周期通常由 JVM 管理,当对象不再被引用时,它就变成了 "垃圾",这些对象占用了内存资源。没有垃圾回收机制,程序员需要手动清理这些不再使用的对象,这可能导致:内存泄漏:程序员没有正确地释放不再使用的对象,导致内存不能被回收。内存溢出:程序分配的内存资源不能及时释放,导致系统内存不足,程序崩溃。

GC 的工作过程大致可以分为两步:

  1. 找到 垃圾,即为不再使用的对象(死亡对象)
  2. 释放 垃圾,该对象所申请的内存释放掉

死亡对象的判断

引用计数法

在 new 对象时,给对象单独添加一个引用计数器:

  • 每当有一个地方引用它,计数器就加 1;
  • 当引用失效(置为 null ),计数器就减 1;
  • 任何时候计数器为 0 的对象就是不可能再被使用的(即为死亡对象)。

这便是 PythonPHP 使用的方法,这个方法实现简单,效率高,但是目前主流的虚拟机中并没有选择这个算法来管理内存,是因为其存在某些致命的缺点。

  • 内存消耗:需要为每个对象都额外开辟一块空间添加计数器,如果一个对象的大小为8字节,计数器的空间通常为4字节,这就比原来多了 50% 的内存空间。
  • 对象之间循环引用:所谓对象之间的相互引用问题,如下面代码所示:除了对象 objAobjB 相互引用着对方之外,这两个对象之间再无任何引用。但是他们因为互相引用对方,导致它们的引用计数器都不为 0,于是引用计数算法无法通知 GC 回收器回收他们。
    public class Test {Object instance = null;public static void main(String[] args) {Test objA = new Test();Test objB = new Test();objA.instance = objB;objB.instance = objA;objA = null;objB = null;}
    }

可达性分析

引用计数法在空间上的开销较大,而可达性分析则是用时间换空间的思想。

  • 以代码中一些特定的对象,作为 GCRoots,也就是遍历的起点,从 GCRoots 开始向下搜索,节点所走过的路径称为引用链,所经过的对象被标记为 “可达”,当一个对象到 GC Roots 没有任何引用链相连的话,该对象则被标记为 “不可达”,则证明此对象是不可用的,需要被回收。
  • 下图为一些对象的引用关系,其中,Obj5 - Obj7 之间虽然有引用关系,但是从 GCRoots开始并不能遍历到 Obj5 - Obj7,被认为不可达,然后回收。
  • 可达性分析 会尽可能的遍历每一个对象,遍历完之后将那些 “不可达” 的对象进行释放。
  • 但是,即使在可达性分析法中不可达的对象,也并非是 “非死不可” 的,这时候它们暂时处于 “缓刑阶段”,要真正宣告一个对象的死亡,至少要经历两次标记过程;可达性分析法中不可达的对象被第一次标记并且进行一次筛选,筛选的条件是此对象是否有必要执行 finalize 方法。当对象没有覆盖 finalize 方法,或 finalize 方法已经被虚拟机调用过时,虚拟机将这两种情况视为没有必要执行。被判定为需要执行的对象将会被放在一个队列中进行第二次标记,除非这个对象与引用链上的任何一个对象建立关联,否则就会被真的回收。
  • Object 类中的 finalize 方法一直被认为是一个糟糕的设计,成为了 Java 语言的负担,影响了 Java 语言的安全和 GC 的性能。JDK9 版本及后续版本中各个类中的 finalize 方法会被逐渐弃用移除。忘掉它的存在吧~~~

❓哪些对象可以作为 GCRoots

  • 虚拟机栈(栈帧中的局部变量表)中引用的对象
  • 本地方法栈(Native 方法)中引用的对象
  • 方法区中类静态属性引用的对象
  • 方法区中常量引用的对象
  • 所有被同步锁持有的对象
  • JNI(Java Native Interface)引用的对象

可达性分析便是 Java 采取的方案,这种方案的弊端也很明显,在每次可达性分析时,都会尽可能的遍历所有对象,如果对象过多,其所消耗的时间也会相应的增长,STW 的时间就会变大。


垃圾收集算法

标记-清除算法

找到可以清除的垃圾对象后,我们还需要对其进行释放。标记-清除算法Mark and Sweep)是最基础的垃圾回收算法。后续的算法都是根据这个算法的缺点进行优化得来的。

  • 它分为两个阶段:
  • 标记阶段:遍历所有对象,标记出哪些对象是可以访问的(即有引用指向的对象)。
  • 清除阶段:回收所有没有标记的对象,释放它们占用的内存。

这个算法的缺点也十分明显。首先体现在效率上,标记和清除这两个过程的效率都不高。再者,从空间上看,标记清除后会产生大量不连续的内存碎片

  • 我们申请内存时,要求这块内存必须是连续的,不能是分散的。
  • 假设你需要申请 1GB 的内存空间,目前空闲内存空间为 4GB,但依然申请失败,这是因为 4GB 的内存大部分都是零零散散分布的,并非连续的。

复制算法

复制算法(Copying)将内存分为两部分:一部分用来存储活动对象,另一部分为空闲区。每次垃圾回收时,将存活的对象复制到另一部分内存上,从而回收掉已经不再使用的内存。

  • 该算法虽然解决了标记-清除算法带来的内存碎片问题。
  • 但需要额外的内存空间,通常是原内存空间的两倍大小,这对于内存的空间利用率是非常低的。
  • 如果存活的对象过多,复制所消耗的时间和资源也是巨大的。

标记-整理算法

标记-整理算法(Mark-Compact)是标记-清除算法的改进版,标记阶段仍然和标记-清除算法相同,但清除阶段不再是直接删除不可达对象,而是将存活对象整理到内存的一端,最后释放出内存的连续空间。

  • 虽然解决了内存碎片的问题以及空间利用率低的问题。
  • 但是相较于标记-清除算法,标记-整理算法的实现更加复杂。
  • 且由于多了整理这一步,因此效率也不高,适合这种垃圾回收频率不是很高的场景

分代收集算法

分代收集算法(Generational Garbage Collection)基于这样一个假设:大部分对象都很快会变成垃圾。因此将堆内存划分为多个区域(如:新生代(伊甸区、幸存区)、老年代),通过将新生代的对象频繁回收来提高回收效率。

  • 堆内存通常被分为以下三个部分:
  1. 新生代内存(Young Generation)
  2. 老生代(Old Generation)
  3. 永久代(Permanent Generation)
  • 下图所示的 Eden(伊甸) 区、两个 Survivor(幸存) 区 S0S1 都属于新生代,中间一层属于老年代,最下面一层属于永久代。JDK 8 版本之后 PermGen(永久) 已被 Metaspace(元空间) 取代,元空间使用的是直接内存,用于存储类元信息、静态变量等。 

分代垃圾回收集具体过程

  • 分代收集算法根据不同 “代” 次区分对象的大小,每进行 GC 一次,每个对象的 “代” 次就会 +1。大多数对象最开始都是 0 代,也就是放在 Eden 区。⚠️每次 Minor GC 后,代数才会 +1。

新生代垃圾回收(Minor GC)

  • 当 Eden 区没有足够空间进行分配时,虚拟机将发起一次 Minor GC(这是一个特殊的 GC)
  • Minor GC 只扫描新生代(而不会扫描整个堆)。
  • 由于大部分对象都存活不到 Minor GC 发生,所以此时所剩的对象也不多,此时 Minor GC 会回收 Eden 中的垃圾对象,存活对象会被复制到 Survivor 区(S0 或 S1)。因为存活对象不多,只需要付出少量对象的复制成本就可以完成每次垃圾收集,所以使用复制算法并不会产生过大的开销。
  • 如果对象在 Eden 出生并经过第一次 Minor GC 后仍然能够存活,并且能被 Survivor 容纳的话,将被移动到 Survivor 空间(s0 或者 s1)中,并将对象代设为 1(Eden 区 -> Survivor 区后对象的初始代数变为 1)。
  • 对于 Survivor 区的对象也会进行 GC 回收,伴随着每次 Minor GC,Survivor 区的对象的 “代” 次也会相应的增加,Survivor 区的对象会在 S0 和 S1 区反复横跳多次 GC 仍存活的对象,达到一定阈值(默认为 15 代)后,晋升到 老年代。⚠️如果 Survivor 区满,存活对象直接晋升到 老年代

老年代垃圾回收(Major GC / Full GC)

  • 当老年代内存不足时(如 Survivor 区晋升过来的对象太多)、显式调用 System.gc() 时、Minor GC 失败(即新生代对象无法晋升到老年代,而老年代已满)时会触发 Major GC
  • 由于老年代的对象可能较少且生命周期都很长,所以使用标记-清除算法标记存活对象并清除不可达对象,且使用标记-整理算法整理存活对象,避免内存碎片。

Full GC

  • Full GC 代表的是 全堆垃圾回收,即 同时回收新生代和老年代
  • 老年代满了(如 Minor GC 失败后,需要腾出老年代空间)、元空间(Metaspace)满了调用 System.gc() 时会触发 Full GC
  • 由于 Full GC 影响较大,因为它会暂停所有线程,通常需要尽量避免。

  • Survivor 区溢出:如果 Survivor 区装不下存活对象,则直接晋升老年代。
  • 大对象直接进入老年代:大对象就是需要大量连续内存空间的对象(比如:字符串、数组)。会直接分配到老年代,避免在新生代频繁移动。
  • 大对象直接进入老年代的行为是由虚拟机动态决定的,它与具体使用的垃圾回收器和相关参数有关。大对象直接进入老年代是一种优化策略,旨在避免将大对象放入新生代,从而减少新生代的垃圾回收频率和成本。

JVM的垃圾回收器 

Java 提供了多种垃圾回收器,常见的有:

Serial GC

  • 特点:单线程工作,所有的垃圾回收工作都由一个线程完成。
  • 适用场景:适合内存较小、单核 CPU 的环境。

Parallel GC(并行回收)

  • 特点:多个线程并行进行垃圾回收,适合多核 CPU 的环境。
  • 适用场景:适合 CPU 核心数多的环境,能显著提高 GC 的吞吐量。

CMS(Concurrent Mark-Sweep)

  • 特点:旨在最小化垃圾回收停顿时间。它通过并行标记阶段和并发清除阶段来减少 GC 停顿时间。
  • 适用场景:适合对响应时间有严格要求的应用,如 Web 应用。

G1 GC(Garbage-First GC)

  • 特点:G1 是一种新型的垃圾回收器,它通过将堆划分为多个区域进行回收,以最小化停顿时间,并保持较高的吞吐量。G1 GC 可以动态调节回收的停顿时间,具有较好的可预测性。
  • 适用场景:适用于大内存和对延迟有较高要求的系统。

  • JVM 机制的介绍到此就结束了,之后更新什么内容之后再说吧~~~
  • 毕竟不知后事如何,且听下回分解 
  • ❤️❤️❤️❤️❤️❤️❤️

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/70910.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

html文件怎么转换成pdf文件,2025最新教程

将HTML文件转换成PDF文件&#xff0c;可以采取以下几种方法&#xff1a; 一、使用浏览器内置功能 打开HTML文件&#xff1a;在Chrome、Firefox、IE等浏览器中打开需要转换的HTML文件。打印对话框&#xff1a;按下CtrlP&#xff08;Windows&#xff09;或CommandP&#xff08;M…

2025 西湖论剑wp

web Rank-l 打开题目环境&#xff1a; 发现一个输入框&#xff0c;看一下他是用上面语言写的 发现是python&#xff0c;很容易想到ssti 密码随便输&#xff0c;发现没有回显 但是输入其他字符会报错 确定为ssti注入 开始构造payload&#xff0c; {{(lipsum|attr(‘global…

Web前端开发--HTML

HTML快速入门 1.新建文本文件&#xff0c;后缀名改为.html 2.编写 HTML结构标签 3.在<body>中填写内容 HTML结构标签 特点 1.HTML标签中不区分大小写 2.HTML标签属性值中可以使用单引号也可使用双引号 3.HTML语法结构比较松散&#xff08;但在编写时要严格一点&…

网络工程师 (30)以太网技术

一、起源与发展 以太网技术起源于20世纪70年代&#xff0c;最初由Xerox公司的帕洛阿尔托研究中心&#xff08;PARC&#xff09;开发。最初的以太网采用同轴电缆作为传输介质&#xff0c;数据传输速率为2.94Mbps&#xff08;后发展为10Mbps&#xff09;&#xff0c;主要用于解决…

ONES 功能上新|ONES Copilot、ONES TestCase、ONES Wiki 新功能一览

ONES Copilot 支持基于当前查看的工作项相关信息&#xff0c;利用 AI 模型&#xff0c;在系统中进行相似工作项的查找&#xff0c;包括基于已关联工作项的相似数据查找。 应用场景&#xff1a; 在查看工作项时&#xff0c;可利用 AI 模型&#xff0c;基于语义相似度&#xff0c…

从 X86 到 ARM :工控机迁移中的核心问题剖析

在工业控制领域&#xff0c;技术的不断演进促使着工控机从 X86 架构向 ARM 架构迁移。然而&#xff0c;这一过程并非一帆风顺&#xff0c;面临着诸多关键挑战。 首先&#xff0c;软件兼容性是一个重要问题。许多基于 X86 架构开发的工业控制软件可能无法直接在 ARM 架构上运行…

《qt open3d网格平滑》

qt open3d网格平滑 效果展示二、流程三、代码效果展示 二、流程 创建动作,链接到槽函数,并把动作放置菜单栏 参照前文 三、代码 1、槽函数实现 void on_actionFilterSmoothSimple_triggered();void MainWindow::on_actionF

Redis 的缓存雪崩、缓存穿透和缓存击穿详解,并提供多种解决方案

本文是对 Redis 知识的补充&#xff0c;在了解了如何搭建多种类型的 Redis 集群&#xff0c;并清楚了 Redis 集群搭建的过程的原理和注意事项之后&#xff0c;就要开始了解在使用 Redis 时可能出现的突发问题和对应的解决方案。 引言&#xff1a;虽然 Redis 是单线程的&#xf…

路由过滤方法与常用工具

引言 在前面我们已经学习了路由引入&#xff0c;接下来我们就更进一步来学习路由过滤 前一篇文章&#xff1a;重发布&#xff1a;路由引入&#xff08;点击即可&#xff09; 路由过滤 定义&#xff1a;路由器在发布或者接收消息时&#xff0c;可能需要对路由信息进行过滤。 作用…

元宵佳节,我的创作纪念日:技术之路的回顾与展望

今天是元宵节&#xff0c;一个象征着团圆与美好的节日。巧合的是&#xff0c;今天也是我作为技术博客博主的创作纪念日。在这个特别的日子里&#xff0c;我想和大家分享我的创作故事&#xff0c;回顾初心、总结收获、展望未来&#xff0c;同时也希望能为正在技术道路上探索的你…

【STM32】H743的以太网MAC控制器的一个特殊功能

调试743的MAC&#xff0c;翻阅手册的时候&#xff0c;发现了一个有意思的功能 混杂模式 H743的MAC控制器&#xff0c;可以设置为混杂模式&#xff0c;这就意味着它可以做一些网络监控的应用&#xff0c;譬如连接具备端口镜像功能的交换机&#xff0c;然后直接代替PC实现网络数据…

一个AI应用的开发、上线流程解析

目录 1. 模型文件格式 1.1 CheckPoint (ckpt) 文件格式 1.2 .pth 文件格式 1.3 .mindir 文件格式 1.4 .onnx 文件格式 2. 推理&#xff08;Inference&#xff09; 2.1.pth (PyTorch模型格式) 2.2 .mindir (MindSpore模型格式) 2.3.onnx (开放神经网络交换格式) 2.4实…

使用grafana v11 建立k线(蜡烛图)仪表板

先看实现的结果 沪铜主力合约 2025-02-12 的1分钟k线图 功能介绍: 左上角支持切换主力合约,日期,实现动态加载数据. 项目背景: 我想通过前端展示期货指定品种某1天的1分钟k线,类似tqsdk 的web_gui 生成图形化界面— TianQin Python SDK 3.7.8 文档 项目架构: 后端: fastap…

【C++】解锁<list>的正确姿势

> &#x1f343; 本系列为初阶C的内容&#xff0c;如果感兴趣&#xff0c;欢迎订阅&#x1f6a9; > &#x1f38a;个人主页:[小编的个人主页])小编的个人主页 > &#x1f380; &#x1f389;欢迎大家点赞&#x1f44d;收藏⭐文章 > ✌️ &#x1f91e; &#x1…

JUC并发—1.Java集合包底层源码剖析

大纲 1.为什么要对JDK源码剖析 2.ArrayList源码一&#xff1a;基本原理以及优缺点 3.ArrayList源码二&#xff1a;核心方法的原理 4.ArrayList源码三&#xff1a;数组扩容以及元素拷贝 5.LinkedList源码一&#xff1a;优缺点和使用场景 6.LinkedList源码二&#xff1a;双…

修改docker内容器中的某配置文件的命令

先找到配置文件config.php find / -name "config.php" 2>/dev/null 然后用vi编辑器修改配置文件 vi /var/www/config.php 最后就是vi的基本操作&#xff0c;根据具体需求使用&#xff1a; vi 有两种主要模式&#xff1a; 命令模式&#xff1a;进入 vi 后的默认…

一竞技瓦拉几亚S4预选:YB 2-0击败GG

在2月11号进行的PGL瓦拉几亚S4西欧区预选赛上,留在欧洲训练的YB战队以2-0击败GG战队晋级下一轮。双方对阵第二局:对线期YB就打出了优势,中期依靠卡尔带队进攻不断扩大经济优势,最终轻松碾压拿下比赛胜利,以下是对决战报。 YB战队在天辉。阵容是潮汐、卡尔、沙王、隐刺、发条。G…

使用Docker部署MySQL 5.7并配置防火墙

步骤1: 切换到超级用户 首先&#xff0c;打开终端&#xff0c;输入以下命令切换到超级用户(root)&#xff1a; su 然后输入您的root密码。 步骤2: 启动Docker服务 确保Docker服务已经启动。可以使用如下命令启动Docker&#xff08;如果它尚未运行&#xff09;&#xff1a;…

vue elementui select下拉库组件鼠标移出时隐藏下拉框

方案&#xff1a; select 监听 mouseleave事件&#xff0c;当鼠标离开时通过唯一标识ref设置select 下拉框隐藏&#xff0c;并做失焦 <el-select v-model"value" :popper-append-to-body"false" class"select_drop_inner" size"sm…

国产操作系统安装DeepSeek

从年前到现在&#xff0c;DeepSeek这款语言AI模型&#xff0c;一经发布直接在全球爆火&#xff0c;在热搜上更是牢牢占据一席之地。无论是技术大神&#xff0c;还是紧跟潮流的技术小白&#xff0c;都被它强大的自然语言处理能力所吸引。作为国产操作系统的用户&#xff0c;千万…