Java 垃圾回收机制详解

1 垃圾回收的概念

垃圾回收(Garbage Collection,GC)是自动管理内存的一种机制,用于释放不再使用的对象所占用的内存空间,防止内存溢出。垃圾回收器通过识别和回收那些已经死亡或长时间未使用的对象,来优化内存的使用。

在 Java 语言出现之前,开发者需要手动管理内存,例如在 C 和 C++ 中,开发者需要编写构造函数和析构函数来创建和销毁对象。Java 引入了垃圾回收机制,简化了内存管理,开发者无需手动释放内存,从而减少了内存泄漏和悬空指针等问题。

2 垃圾判断算法

在 Java 虚拟机(JVM)中,垃圾回收器需要判断哪些对象是垃圾,哪些对象仍然存活。垃圾判断算法是垃圾回收机制的核心部分,常见的算法包括引用计数算法可达性分析算法

2.1 引用计数算法

引用计数算法(Reference Counting)通过在对象头中维护一个引用计数器来记录对象被引用的次数。每当对象被引用时,引用计数器加 1;当引用被删除时,引用计数器减 1。当引用计数器为 0 时,对象被认为是垃圾,可以被回收。

2.1.1 示例

String s = new String("沉默王二");
s = null; // 引用计数为 0,对象可以被回收

在这个例子中,字符串对象 "沉默王二" 最初被 s 引用,引用计数为 1。当 s 被设置为 null 时,引用计数变为 0,对象可以被回收。

2.1.2 优点

  • 实时性:引用计数算法将垃圾回收分散到应用程序的运行过程中,而不是集中在垃圾收集时,因此不会导致“Stop-The-World”事件。

2.1.3 缺点

  • 循环引用问题:引用计数算法无法解决循环引用的问题。如果两个对象相互引用,即使它们不再被外部引用,它们的引用计数也不会为 0,导致无法被回收。

2.1.4 循环引用示例

public class ReferenceCountingGC {public Object instance;public static void testGC() {ReferenceCountingGC a = new ReferenceCountingGC();ReferenceCountingGC b = new ReferenceCountingGC();a.instance = b;b.instance = a;a = null;b = null;}
}

在这个例子中,ab 相互引用,导致它们的引用计数永远不会为 0,即使它们已经不再被外部引用,也无法被回收。

2.2 可达性分析算法

可达性分析算法(Reachability Analysis)通过从一组称为 GC Roots 的对象开始,遍历对象图,标记所有可达的对象。不可达的对象被认为是垃圾,可以被回收。

2.2.1 GC Roots

GC Roots 是一组必须活跃的引用,它们是程序运行时的起点,是一切引用链的源头。在 Java 中,GC Roots 包括以下几种:

  1. 虚拟机栈中的引用:方法的参数、局部变量等。
  2. 本地方法栈中 JNI 的引用:通过 JNI(Java Native Interface)调用的本地代码中的引用。
  3. 类静态变量:类的静态属性引用的对象。
  4. 运行时常量池中的常量:字符串常量或类类型常量。

2.2.2 示例

  1. 虚拟机栈中的引用
public class StackReference {public void greet() {Object localVar = new Object(); // 局部变量,存在于虚拟机栈中System.out.println(localVar.toString());}public static void main(String[] args) {new StackReference().greet();}
}

在这个例子中,localVar 是一个局部变量,存在于虚拟机栈中,可以被认为是 GC Roots。在 greet 方法执行期间,localVar 引用的对象是活跃的。当 greet 方法执行完毕后,localVar 的作用域结束,引用的对象将不再被 GC Roots 引用,因此可以被回收。

  1. 本地方法栈中 JNI 的引用
public native void nativeMethod();JNIEXPORT void JNICALL Java_NativeExample_nativeMethod(JNIEnv *env, jobject thisObj) {jobject localRef = (*env)->NewObject(env, ...); // 本地方法栈中的 JNI 引用
}

在这个例子中,localRef 是一个 JNI 引用,存在于本地方法栈中。在本地方法执行期间,localRef 引用的对象是活跃的。一旦本地方法执行完毕,除非 localRef 是全局的,否则它引用的对象将被回收。

  1. 类静态变量
public class StaticFieldReference {private static Object staticVar = new Object(); // 类静态变量public static void main(String[] args) {System.out.println(staticVar.toString());}
}

在这个例子中,staticVar 是一个类静态变量,引用的对象存储在元空间中,可以被认为是 GC Roots。只要 StaticFieldReference 类未被卸载,staticVar 引用的对象就不会被回收。

  1. 运行时常量池中的常量
public class ConstantPoolReference {public static final String CONSTANT_STRING = "Hello, World"; // 字符串常量public static final Class<?> CONSTANT_CLASS = Object.class; // 类类型常量public static void main(String[] args) {System.out.println(CONSTANT_STRING);System.out.println(CONSTANT_CLASS.getName());}
}

在这个例子中,CONSTANT_STRINGCONSTANT_CLASS 是运行时常量池中的常量,它们引用的对象可以被认为是 GC Roots。只要 ConstantPoolReference 类未被卸载,这些常量引用的对象就不会被回收。

2.3 小结

  • 引用计数算法通过维护对象的引用计数来判断对象是否可以被回收,但它无法解决循环引用的问题。
  • 可达性分析算法通过从 GC Roots 开始遍历对象图,标记所有可达的对象,解决了循环引用的问题。

在 Java 中,垃圾回收器通常使用可达性分析算法来判断对象是否可以被回收。GC Roots 包括虚拟机栈中的引用、本地方法栈中的 JNI 引用、类静态变量和运行时常量池中的常量。

3 垃圾收集算法

在确定了哪些对象是垃圾之后,垃圾收集器需要选择合适的算法来回收这些垃圾。垃圾收集算法的设计目标是高效地回收垃圾,同时尽量减少对应用程序性能的影响。常见的垃圾收集算法包括标记-清除算法复制算法标记-整理算法分代收集算法

3.1 标记-清除算法(Mark-Sweep)

标记-清除算法是最基础的垃圾回收算法,分为两个阶段:

  1. 标记阶段:垃圾收集器从 GC Roots 开始,遍历所有可达的对象,并标记这些对象为存活对象。
  2. 清除阶段:垃圾收集器清除所有未被标记的对象,即垃圾对象。

优点

  • 实现简单:标记-清除算法的逻辑清晰,易于实现。

缺点

  • 内存碎片问题:清除阶段只是简单地回收垃圾对象,不会对内存进行整理,导致内存碎片化。内存碎片化可能会导致在分配大对象时无法找到足够的连续内存,从而触发新一轮的垃圾收集。

3.2 复制算法(Copying)

复制算法是为了解决标记-清除算法的内存碎片问题而设计的。它将可用内存划分为大小相等的两块区域,每次只使用其中一块。

  1. 复制阶段:当一块内存用完后,垃圾收集器将存活的对象复制到另一块内存中。
  2. 清理阶段:复制完成后,垃圾收集器清理已使用过的内存区域。

优点

  • 内存连续性:复制算法保证了内存的连续性,避免了内存碎片问题。
  • 高效性:由于只需要复制存活的对象,复制算法的效率较高。

缺点

  • 内存利用率低:复制算法只能利用一半的内存空间,另一半内存始终处于空闲状态,导致内存利用率较低。

3.3 标记-整理算法(Mark-Compact)

标记-整理算法结合了标记-清除算法和复制算法的优点,分为三个阶段:

  1. 标记阶段:与标记-清除算法相同,垃圾收集器标记所有可达的对象。
  2. 整理阶段:将所有存活的对象移动到内存的一端,确保内存的连续性。
  3. 清理阶段:清理掉端边界以外的内存区域。

优点

  • 解决内存碎片问题:标记-整理算法通过整理内存,避免了内存碎片问题。
  • 内存利用率高:与复制算法不同,标记-整理算法可以利用全部内存空间。

缺点

  • 效率较低:整理阶段需要移动所有存活的对象,导致效率较低。

3.4 分代收集算法(Generational Collection)

分代收集算法并不是一种独立的算法,而是根据对象的存活周期将内存划分为不同的代(通常是新生代老年代),并根据各代的特点采用不同的垃圾收集算法。

3.4.1 新生代(Young Generation)

  • 特点:新生代中的对象通常存活时间较短,大部分对象在创建后很快就会变成垃圾。
  • 算法:由于新生代中大部分对象是短命的,垃圾收集器通常采用复制算法。新生代进一步分为 Eden 区和两个 Survivor 区(From 和 To)。每次垃圾收集时,存活的对象从 Eden 区和 From 区复制到 To 区,然后清理 Eden 区和 From 区。

3.4.2 老年代(Old Generation)

  • 特点:老年代中的对象通常存活时间较长,对象存活率高。
  • 算法:由于老年代中的对象存活率高,垃圾收集器通常采用标记-清除算法标记-整理算法。老年代的垃圾收集称为 Major GC,通常会触发“Stop-The-World”事件。

优点

  • 优化性能:分代收集算法根据对象的存活周期选择合适的垃圾收集算法,从而优化垃圾收集的性能。
  • 减少停顿时间:通过将内存划分为不同的代,垃圾收集器可以更频繁地进行 Minor GC(新生代垃圾收集),减少 Major GC 的频率,从而减少停顿时间。

3.5 小结

  • 标记-清除算法是最基础的垃圾回收算法,但存在内存碎片问题。
  • 复制算法解决了内存碎片问题,但内存利用率较低。
  • 标记-整理算法结合了标记-清除和复制算法的优点,解决了内存碎片问题,但效率较低。
  • 分代收集算法根据对象的存活周期将内存划分为不同的代,并采用不同的垃圾收集算法,从而优化垃圾收集的性能。

不同的垃圾收集算法适用于不同的场景,垃圾收集器的设计需要在内存利用率、垃圾收集效率和停顿时间之间找到平衡。

4 新生代和老年代

在 Java 虚拟机(JVM)中,堆(Heap)是最大的一块内存区域,也是垃圾收集器管理的主要区域。堆内存被划分为新生代(Young Generation)老年代(Old Generation),其中新生代又进一步分为 Eden 区和两个 Survivor 区(From 和 To)。

4.1 新生代(Young Generation)

4.1.1 Eden 区

根据 IBM 的研究,大约 98% 的对象是“朝生夕死”的,即这些对象在创建后很快就会变成垃圾。因此,大多数对象在新生代的 Eden 区中分配。

  • 对象分配:当对象被创建时,首先在 Eden 区中分配内存。
  • Minor GC:当 Eden 区没有足够的空间分配新对象时,JVM 会触发一次 Minor GC(新生代垃圾收集)。Minor GC 的频率较高,回收速度也较快。
  • 存活对象处理:在 Minor GC 之后,Eden 区中绝大部分对象会被回收,而那些存活的对象会被移动到 Survivor 区的 From 区。如果 From 区空间不足,存活对象会直接进入 To 区

4.1.2 Survivor 区

Survivor 区是新生代中的一个缓冲区,分为 From 区To 区。它的主要作用是减少对象直接进入老年代的频率,从而减少 Major GC 的发生。

4.1.3 为什么需要 Survivor 区?

如果没有 Survivor 区,Eden 区每进行一次 Minor GC,存活的对象就会被直接送到老年代。这样会导致老年代很快被填满,进而频繁触发 Major GC。然而,很多对象虽然在一次 Minor GC 中存活下来,但可能在第二次或第三次 Minor GC 中就会被回收。因此,直接将这些对象送入老年代并不是一个明智的选择。

Survivor 区的存在意义在于:

  • 减少进入老年代的对象:Survivor 区通过预筛选机制,确保只有那些在多次 Minor GC 中存活下来的对象才会被晋升到老年代。
  • 减少 Major GC 的频率:通过减少进入老年代的对象数量,Survivor 区有效地减少了 Major GC 的发生频率。

4.1.4 Survivor 区为什么分为两块?

Survivor 区分为两块(From 和 To)的主要目的是解决内存碎片化问题。

  • 内存碎片化问题:如果没有 Survivor 区,或者 Survivor 区只有一个区域,那么在 Minor GC 后,Eden 区被清空,存活的对象被放入 Survivor 区。此时,Survivor 区中可能存在一些需要被回收的对象。在这种情况下,垃圾收集器只能采用标记-清除算法,这会导致内存碎片化。

  • 双 Survivor 区的优势:通过设置两个 Survivor 区,每次 Minor GC 时,存活的对象会从 Eden 区和 From 区复制到 To 区。第二次 Minor GC 时,From 区和 To 区的角色互换,存活的对象从 Eden 区和 To 区复制到 From 区。这种机制确保了在任何时候,总有一个 Survivor 区是空的,另一个 Survivor 区是无碎片的。

  • 为什么不是更多块?:如果 Survivor 区被划分为更多块,每一块的空间会变得更小,容易导致 Survivor 区满,进而增加对象进入老年代的频率。两块 Survivor 区是经过权衡后的最佳方案。

4.2 老年代(Old Generation)

老年代占据堆内存的 2/3,主要用于存放存活时间较长的对象。老年代的垃圾收集称为 Major GC,每次 Major GC 都会触发“Stop-The-World”事件,即暂停所有用户线程,直到垃圾收集完成。

4.2.1 老年代的垃圾收集算法

由于老年代中的对象存活率较高,复制算法在老年代中效率较低,因此老年代通常采用 标记-整理算法标记-清除算法

  • 标记-整理算法:将所有存活的对象移动到内存的一端,然后清理掉端边界以外的内存区域,避免了内存碎片问题。
  • 标记-清除算法:标记所有存活的对象,然后清除未标记的对象,但可能会导致内存碎片。

4.2.2 对象进入老年代的条件

除了通过内存担保机制将无法安置的对象直接进入老年代外,以下几种情况也会导致对象进入老年代:

  1. 大对象

大对象是指需要大量连续内存空间的对象。这类对象不管其生命周期长短,都会直接进入老年代。这是为了避免在 Eden 区和 Survivor 区之间进行大量的内存复制操作。

  1. 长期存活对象

JVM 为每个对象定义了一个 对象年龄(Age)计数器。对象在 Survivor 区中每经历一次 Minor GC,年龄就会增加 1 岁。当对象的年龄达到某个阈值(默认是 15 岁)时,它会被晋升到老年代。

  • 年龄阈值设置:可以通过 JVM 参数 -XX:MaxTenuringThreshold 来调整对象晋升到老年代的年龄阈值。默认值为 15,但可以通过以下命令查看:

    java -XX:+PrintFlagsFinal -version | grep MaxTenuringThreshold
    
  1. 动态对象年龄

JVM 并不强制要求对象必须达到 15 岁才能进入老年代。如果 Survivor 区中某个年龄段的对象总大小超过了 Survivor 区的一半,那么该年龄段及以上年龄段的所有对象都会在下一次垃圾回收时被晋升到老年代。

这种动态调整机制类似于负载均衡中的动态调度算法,能够根据对象的实际存活情况优化内存使用,减少垃圾收集的频率。

4.3 小结

  • 新生代:大多数对象在 Eden 区中分配,经过 Minor GC 后,存活的对象会被移动到 Survivor 区。Survivor 区分为 From 和 To 两个区域,用于减少内存碎片化,并减少对象进入老年代的频率。
  • 老年代:老年代用于存放存活时间较长的对象,垃圾收集采用标记-整理或标记-清除算法。对象进入老年代的条件包括大对象、长期存活对象和动态对象年龄。

通过合理的内存划分和垃圾收集算法,JVM 能够在保证内存利用率的同时,减少垃圾收集的停顿时间,从而提高应用程序的性能。

5 Stop The World

在 Java 垃圾收集(Garbage Collection,GC)过程中,“Stop The World” 是一个重要的概念。它指的是在垃圾收集器执行垃圾回收时,JVM 会暂停所有的用户线程(即应用程序线程),直到垃圾收集完成。这种暂停被称为 “Stop The World” 事件。

5.1 为什么需要 “Stop The World”?

“Stop The World” 的主要目的是确保垃圾收集器能够准确地识别和回收垃圾对象。如果在垃圾收集过程中,用户线程继续运行并修改堆中的对象,可能会导致以下问题:

  1. 对象状态不一致:用户线程可能会修改对象的引用关系,导致垃圾收集器无法正确判断对象的可达性。
  2. 内存泄漏或误回收:如果垃圾收集器在收集过程中无法准确识别对象的引用关系,可能会导致某些对象被错误地回收(即本应存活的对象被回收),或者某些垃圾对象未被回收(即内存泄漏)。

因此,为了确保垃圾收集的准确性,JVM 在执行垃圾收集时会暂停所有用户线程,即触发 “Stop The World” 事件。

5.2 “Stop The World” 的影响

“Stop The World” 事件会对 Java 应用程序的性能产生显著影响,尤其是在停顿时间较长的情况下:

  • 响应时间变长:如果垃圾收集器的停顿时间过长,应用程序的响应时间会显著增加,尤其是在对实时性要求较高的应用中,如交易系统、游戏服务器等,这种情况是不可接受的。
  • 用户体验下降:对于用户交互频繁的应用程序(如 Web 应用或桌面应用),长时间的停顿会导致用户体验下降,甚至可能导致用户认为应用程序无响应。

5.3 减少 “Stop The World” 的策略

为了减少 “Stop The World” 事件对应用程序性能的影响,Java 提供了多种垃圾收集器,并引入了并发垃圾收集技术。以下是一些常见的策略:

5.3.1 并发垃圾收集器

并发垃圾收集器(如 G1(Garbage First)ZGC(Z Garbage Collector))通过并发执行垃圾收集任务,尽量减少 “Stop The World” 的停顿时间。

  • G1 收集器:G1 收集器通过将堆内存划分为多个区域(Region),并采用并发标记和混合收集的方式,减少了停顿时间。G1 的目标是让停顿时间控制在用户指定的范围内(通过 -XX:MaxGCPauseMillis 参数设置)。
  • ZGC 收集器:ZGC 是一种低延迟的垃圾收集器,它的设计目标是让停顿时间不超过 10 毫秒。ZGC 通过并发执行大部分垃圾收集任务,显著减少了 “Stop The World” 的影响。

5.3.2 分代收集

分代收集算法将堆内存划分为新生代和老年代,并根据对象的存活周期采用不同的垃圾收集策略。新生代中的对象通常存活时间较短,因此垃圾收集器可以更频繁地进行 Minor GC,而老年代中的对象存活时间较长,垃圾收集器会减少 Major GC 的频率。

通过分代收集,垃圾收集器可以更高效地管理内存,减少 “Stop The World” 事件的发生频率。

5.3.3 增量式垃圾收集

增量式垃圾收集器通过将垃圾收集任务分解为多个小任务,并在应用程序运行的间隙中逐步执行这些任务,从而减少 “Stop The World” 的停顿时间。

5.3.4 并行垃圾收集

并行垃圾收集器(如 Parallel GC)通过多线程并行执行垃圾收集任务,加快垃圾收集的速度,从而减少停顿时间。虽然并行垃圾收集器仍然会触发 “Stop The World” 事件,但它通过并行处理提高了垃圾收集的效率。

5.4 小结

“Stop The World” 是 Java 垃圾收集过程中不可避免的一个挑战。它确保了垃圾收集器能够准确地识别和回收垃圾对象,但同时也会对应用程序的性能产生影响。为了减少 “Stop The World” 的停顿时间,Java 提供了多种垃圾收集器(如 G1 和 ZGC),并通过并发、分代和增量式垃圾收集等技术,尽量减少对应用程序性能的影响。

在实际应用中,开发者需要根据应用程序的性能需求和内存使用情况,选择合适的垃圾收集器,并通过调优参数(如 -XX:MaxGCPauseMillis)来平衡内存的有效利用和应用程序的响应性能。

6 总结

Java 的垃圾回收机制通过自动管理内存,简化了开发者的内存管理工作。垃圾回收器通过引用计数算法和可达性分析算法判断垃圾对象,并使用标记清除、复制、标记整理和分代收集等算法进行垃圾回收。新生代和老年代的划分进一步优化了垃圾回收的效率。尽管“Stop The World”事件会对性能产生影响,但现代垃圾收集器通过并发收集技术,尽量减少了停顿时间。

7 思维导图

在这里插入图片描述

8 参考链接

深入理解 JVM 的垃圾回收机制

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

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

相关文章

车载终端_智能车载终端定制_农机/出租车/叉车/驾培车载终端MTK方案

车载终端集成了先进的技术和卓越的性能&#xff0c;采用了联发科的高效低功耗ARM处理器&#xff0c;具备八核架构&#xff0c;主频高达2.0GHz&#xff0c;基于12nm制程工艺&#xff0c;不仅性能强劲&#xff0c;而且功耗控制出色。基本配置为4GB内存与64GB存储&#xff0c;用户…

【JavaSE基础】第十七章:反射+设计模式

一、反射 1.反射(Reflection)&#xff1a;允许在程序运行状态中&#xff0c;可以获取任意类中的属性和方法&#xff0c;并且可以操作任意对象内部的属性和方法&#xff0c;这种动态获取类的信息及动态操作对象的属性和方法对应的机制称为反射机制。 2.类对象 和 类的对象(实例…

Scratch教学作品 | 3D圆柱体俄罗斯方块——旋转视角的全新挑战! ✨

今天为大家推荐一款创意十足的Scratch益智游戏——《3D圆柱体俄罗斯方块》&#xff01;由Ceratophrys制作&#xff0c;这款作品将经典俄罗斯方块与立体圆柱舞台相结合&#xff0c;为玩家带来了前所未有的空间挑战与乐趣。更棒的是&#xff0c;这款游戏的源码可以在小虎鲸Scratc…

三维空间刚体运动4-1:四元数表示变换(各形式相互转换加代码——下篇)

三维空间刚体运动4-1&#xff1a;四元数表示变换&#xff08;各形式相互转换加代码——下篇&#xff09; 4. 四元数到其它旋转表示的相互转换4.1 旋转向量4.2 旋转矩阵4.3 欧拉角4.3.1 转换关系4.3.2 转换中的万象锁问题 5. 四元数的其他性质5.1 旋转的复合5.2 双倍覆盖5.3 指数…

使用layui的table提示Could not parse as expression(踩坑记录)

踩坑记录 报错图如下 原因&#xff1a; 原来代码是下图这样 上下俩中括号都是连在一起的&#xff0c;可能导致解析问题 改成如下图这样 重新启动项目&#xff0c;运行正常&#xff01;

大模型的构建与部署(2)——数据清洗

版权声明 本文原创作者:谷哥的小弟作者博客地址:http://blog.csdn.net/lfdfhl1. 数据清洗的必要性与影响 1.1 数据清洗对模型性能的影响 数据清洗是数据预处理的关键步骤,对于模型训练的性能和准确性有着直接的影响。原始数据中的缺失值、重复值、异常值以及数据格式不一致…

【MySQL】--- 数据库基础

Welcome to 9ilks Code World (๑•́ ₃ •̀๑) 个人主页: 9ilk (๑•́ ₃ •̀๑) 文章专栏&#xff1a; MySQL 本篇博客我们来建立一下数据库的相关概念&#xff0c;主要理解什么是数据库以及mysql和mysqld&#xff0c;MySQL架构等问题。 &#x1f3e0; 登录…

Vue中纯前端实现导出简单Excel表格的功能

Vue 前端Excel导出 Vue中纯前端导出简单Excel表格的方法(使用vue-json-excel插件) 前言 在许多的后台系统中少不了导出Excel表格的功能&#xff0c;在项目中纯前端使用vue-json-excel插件来实现简单Excel表格的导出功能。 使用方法 1、安装依赖 npm install vue-json-exc…

KeyFormer:使用注意力分数压缩KV缓存

Keyformer: KV Cache Reduction through Key Tokens Selection for Efficient Generative Inference 202403&#xff0c;发表在Mlsys Introduction 优化KV cache的策略&#xff0c;主要是集中在系统级别的优化上&#xff0c;比如FlashAttention、PagedAttention&#xff0c;它…

Linux 权限管理实践:精确控制用户对 systemctl 和 journalctl 命令的使用

前言 在 Linux 系统管理中&#xff0c;精确控制用户对特定命令的访问权限是一项关键的安全实践。使用 systemctl 和 journalctl 命令时&#xff0c;不当的权限设置可能会导致不必要的风险。本篇博客将详细讨论如何通过 sudoers 文件和 Polkit 策略为不同用户配置 systemctl 和…

SSH连接成功,但VSCode连接不成功

环境 在实验室PC上连接服务器234 解决方案&#xff1a;在VSCode中重新添加远程主机 删除旧的VSCode Server 在远程主机上&#xff0c;VSCode会安装一个‘vscode-server’服务来支持远程开发&#xff0c;有时旧的‘vscode-server’文件可能会导致问题&#xff0c;删除旧的&am…

【Qt】qt安装

在工作一年之后&#xff0c;还是想做一个Qt的教程&#xff0c;遥想研一刚刚接触Qt&#xff0c;从0到1学习&#xff0c;没有什么参考书籍&#xff0c;网上的资料也不多&#xff0c;幸好Qt官方文档写得好&#xff0c;加上自己肯研究&#xff0c;才堪堪入门。 现在我想自己写一个…

Web开发 -前端部分-CSS

CSS CSS&#xff08;Cascading Style Sheet&#xff09;:层叠样式表&#xff0c;用于控制页面的样式&#xff08;表现&#xff09;。 一 基础知识 1 标题格式 标题格式一&#xff1a; 行内样式 <!DOCTYPE html> <html lang"en"><head><meta…

YOLOv8目标检测(六)_封装API接口

YOLOv8目标检测(一)_检测流程梳理&#xff1a;YOLOv8目标检测(一)_检测流程梳理_yolo检测流程-CSDN博客 YOLOv8目标检测(二)_准备数据集&#xff1a;YOLOv8目标检测(二)_准备数据集_yolov8 数据集准备-CSDN博客 YOLOv8目标检测(三)_训练模型&#xff1a;YOLOv8目标检测(三)_训…

51c视觉~YOLO~合集6~

我自己的原文哦~ https://blog.51cto.com/whaosoft/12830685 一、其他yolo 1.1 Spiking-YOLO​ 使用常规深度神经网络到脉冲神经网络转换方法应用于脉冲神经网络域时&#xff0c;性能下降的很多&#xff0c;深入分析后提出了可能的解释&#xff1a;一是来自逐层归一化的效率…

如何在 Ubuntu 22.04 上安装 Strapi CMS

简介 Strapi 是一个使用 JavaScript 构建的开源、无头内容管理系统 (CMS)。与其他无头 CMS 一样&#xff0c;Strapi 开箱即用不带前端。它使用 API 作为其前端&#xff0c;允许你使用流行的框架&#xff08;如 React 和 Next.js&#xff09;构建网站。Strapi 基于插件系统&…

数字IC后端零基础入门基础理论(Day1)

数字IC后端设计导入需要用到的input数据如下图所示。 数字后端零基础入门系列 | Innovus零基础LAB学习Day9 Netlist: 设计的Gate level&#xff08;门级&#xff09;网表。下图所示为一个计数器设计综合后的门级netlist。 从这个netlist中我们看到这个设计顶层的名字叫counte…

序列模型的使用示例

序列模型的使用示例 1 RNN原理1.1 序列模型的输入输出1.2 循环神经网络&#xff08;RNN&#xff09;1.3 RNN的公式表示2 数据的尺寸 3 PyTorch中查看RNN的参数4 PyTorch中实现RNN&#xff08;1&#xff09;RNN实例化&#xff08;2&#xff09;forward函数&#xff08;3&#xf…

WSL2内部的Ubuntu怎么设置网络内桥接模式,弄了好久老是不成功,怎么办?

环境: Win10专业版 WSL2 Ubuntu22.04 问题描述: WSL2内部的Ubuntu怎么设置网络内桥接模式 解决方案: 方法一 1.控制面板开启,Hyper-V 管理器 2.重启电脑 3…创建外部虚拟交换机 打开 Hyper-V 管理器,在右侧操作面板中点击“虚拟交换机管理器”。 选择“创建虚…

redis集群 服务器更换ip,怎么办,怎么更换redis集群的ip

redis集群 服务器更换ip&#xff0c;怎么办&#xff0c;怎么更换redis集群的ip 1、安装redis三主三从集群2、正常状态的redis集群3、更改redis集群服务器的ip 重启服务器 集群会down4、更改redis集群服务器的ip 重启服务器 集群down的原因5、更改redis集群服务器的ip后&#xf…