JVM-垃圾回收(标记算法,收集器)

news2024/11/23 12:36:36

申明:文章内容是本人学习极客时间课程所写,文字和图片基本来源于课程资料,在某些地方会插入一点自己的理解,未用于商业用途,侵删。
原资料地址:课程资料

垃圾回收的基本原理

1 什么是垃圾?
在内存中,没有被引用的对象就是垃圾。
2 如果找到垃圾对象?

  • 引用计数法
    遍历堆中的对象是不是被引用了,如果没有就是垃圾对象。当这个对象引用都消失了,消失一个计数减一,当引用都消失了,计数就会变为0。此时这个对象就会变
    成垃圾
    • 单一引用
    • 循环引用
    • 无引用
      存在的问题是如果存在循环引用,则永远无法识别到这是垃圾对象。
  • 跟可达算法
    又叫根搜索算法。在主流的商用程序语言中(Java和C#),都是使用根搜索算法判定对象是否存活的。
    基本思路就是通过一系列的名为“GCRoot”的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链(Reference Chain),当一个对象到GCRoot没有任何引用链相连时,则证明此对象是不可用的,也就是不可达的。
    可作GCRoots的对象(也就是从这个根去找看能不能找到一个引用链):
    虚拟机栈中,栈帧的本地变量表引用的对象。
    方法区中,类静态属性引用的对象。
    方法区中,常量引用的对象。
    本地方法栈中,JNl引用的对象。
    3 如何进行回收?
    即使在可达性分析算法中不可达的对象,也并非是“非死不可”。被判定不可达的对象处于“缓刑”阶段。要真正宣告死亡,至少要经历两次标记过程:
    第一次标记:如果对象可达性分析后,发现没有与GC Roots相连接的引用链,那它将会被第一次标记;
    第二次标记:第一次标记后,接着会进行一次筛选。筛选条件:此对象是否有必要执行finalize() 方法。在 finalize() 方法中没有重新与引用链建立关联关系的,将被进行第二次标记。
    第二次标记成功的对象将真的会被回收,如果失败则继续存活(也就是两次执行了finalize,这个对象一定被回收)
/**
  * 演示:
  * 1.对象可以在被GC时自我拯救。
  * 2.机会只有一次,对象的finalize()方法只会被系统自动调用一次
  */
 public static T11 SAVE_HOOK = null;

 public static void main(String[] args) throws Throwable {
     SAVE_HOOK = new T11();
     //对象第一次成功拯救自己
     SAVE_HOOK = null;
     System.gc();
     //因为finalize方法优先级很低,所以暂停0.5秒以等待它
     Thread.sleep(500);
     if (SAVE_HOOK != null) {
         SAVE_HOOK.isAlive();
     } else {
         System.out.println("被回收了");
     }
     //下面这段代码与上面的完全相同,但是这次自救却失败了
     SAVE_HOOK = null;
     System.gc();
     //因为finalize方法优先级很低,所以暂停0.5秒以等待它
     Thread.sleep(500);
     if (SAVE_HOOK != null) {
         SAVE_HOOK.isAlive();
     } else {
         System.out.println("被回收了");
     }
 }
 public void isAlive() {
     System.out.println("仍然没有被回收!");
 }

 @Override
 protected void finalize() throws Throwable {
     super.finalize();
     System.out.println("执行 finalize() !");
     // 让这个对对象重新有引用
     T11.SAVE_HOOK = this;
 }

在这里插入图片描述
过程是这样:首先有引用,然后将引用设置为空,这个对象在一定时间内会执行finalize,在finalize中重新给它引用,这样对象又会存活,但是这种机制只能使用一次,第二次执行finalize方法这个对象就一定会被回收

对象引用

在JDK1.2之后,Java对引用的概念进行了扩充,将引用分为强引用(StrongReference)、软引用(SoftReference)、弱引用(WeakReference)、虚引用(PhantomReference)四种,这四种引用强度依次逐渐减弱。
在这里插入图片描述

  1. 强引用
    代码中普遍存在,只要强引用还在,就不会被GC。
Object obj = new Object();
  1. 软引用
    非必须引用,内存溢出之前进行回收,如内存还不够,才会抛异常。
Object obj = new Object();
SoftReference<Object> sf = new SoftReference<Object>(obj);
// 去掉强引用
obj = null;
//有时候会返回null,因为有可能这个对象被回收了
Object o = sf.get();

应用场景:软引用可用来实现内存敏感的高速缓存。
引用场景:
应用需要读取大量本地文件,如果每次读取都从硬盘读取会严重影响性能,如果一次性全部加载到内存,内存可能会溢出。
可以使用软引用解决这个问题,使用一个HashMap来保存文件路径和文件对象管理的软引用之间的映射关系.
内存不足时,JVM会自动回收缓存文件对象的占用空间,有效地避免了OOM问题。

// 也就是说我们先缓存文件,如果内存不够用了这个时候就会释放这部分空间
// 那查找的时候就需要注意如果这个map中没有那么就要重新从磁盘中去加载
Map<String, SoftReference<Bitmap>> fileCache = new HashMap<String,SoftReference<Bitmap>>
  1. 弱引用
    非必须引用,只要有GC,就会被回收。
Object obj = new Object();
WeakReference<Object> wf = new WeakReference<Object>(obj);
obj = null;
System.gc();
//有时候会返回null
Object o = wf.get();
//返回是否被垃圾回收器标记为即将回收的垃圾
boolean enqueued = wf.isEnqueued();

ThreadLocal里面用到了弱引用
弱引用是在第二次垃圾回收时回收,短时间内通过弱引用取对应的数据,可以取到,当执行过第二次垃圾回收时,将返回null。
作用:监控对象是否已经被垃圾回收器标记为即将回收的垃圾,可以通过弱引用的isEnQueued方法返回对象是否被垃圾回收器标记。
4. 虚引用
虚引用是最弱的一种引用关系。垃圾回收时直接回收
一个对象是否有虚引用的存在,完全不会对其生存时间构成影响,也无法通过虚引用来取得一个对象实例。
虚引用是每次垃圾回收的时候都会被回收,通过虚引用的get方法永远获取到的数据为null,因此也被成为幽灵引用。
作用:跟踪对象被垃圾回收的状态,仅仅是提供一种确保对象被回收后,做某些事情的机制。类似事件监听机制

Object obj = new Object();
PhantomReference<Object> pf = new PhantomReference<Object>(obj, new
ReferenceQueue<>());
// 去掉强引用
obj=null;
//永远返回null 
Object o = pf.get();
boolean enqueued = pf.isEnqueued();//返回是否从内存中已经删除

垃圾清除算法

1、标记-清除算法(Mark-Sweep) “标记-清除”算法是最基础的算法,分为“标记”和“清除”两个阶段:首先标记出所有需要回收的对象,在标记完成后统一回收掉所有被标记的对象。
它主要由两个缺点:一个是效率问题,标记和清除过程的效率都不高;另一个是空间问题,标记清除之后会产生大量不连续的内存碎片,空间碎片太多可能会导致当程序在以后的运行过程中需要分配较大对象时无法找到足够的连续内存而不得不提前触发另一次垃圾收集动作。
在这里插入图片描述

2、复制算法(Copying)(针对新生代) 为了解决标记清除算法的效率问题,出现了复制算法,它将可用内存按容量划分为大小相等的两块,每次使用其中的一块。当这块的内存用完了,就将还存活着的对象复制到另一块上面,然后再把已使用过的内存空间一次清理掉。
优点:是每次都是对其中的一块进行内存回收,内存分配时就不用考虑内存碎片等复杂情况,只要移动堆顶指针,按顺序分配内存即可,实现简单,运行高效。
缺点:是将内存缩小为原来的一半,代价太高了一点。
在这里插入图片描述
存活的对象全在一边。现在商业虚拟机都是采用这种收集算法来回收新生代,当回收时,将Eden和Survivor中还存活着的对象拷贝到另外一块Survivor空间上,最后清理掉Eden和刚才用过的Survivor的空间。 HotSpot虚拟机默认Eden和Survivor的大小比例是8:1,也就是每次新生代中可用内存空间为整个新生代容量的90%(80%+10%),只有10%的内存是会被“浪费的。当Survivor空间不够用时,需要依赖其他内存(这里指老年代)进行分配担保(Handle Promotion)。

3、标记-整理算法(Mark-Compact)(针对老年代) 复制收集算法在对象存活率较高时就需要执行较多的复制操作,效率将会变低。更关键的是,如果不想浪费50%的空间,就需要有额外的空间进行分配担保(老年代给年轻代担保,但是没有人给老年代担保),以应对被使用的内存中所有对象都100%存活的极端情况,所以在老年代一般不能直接选用复制收集算法。
根据老年代的特点提出了“标记-整理”算法,标记过程仍然与“标记-清除”算法一样,但后续步骤不是直接对可回收对象进行清理,而是让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存,因为老年代是FLLGC所以也能接受这种复制带来的效率低下。
标记-整理的步骤: 标记阶段 整理阶段:移动存活对象,同时更新存活对象中所有指向被移动对象的指针
缺点:性能较低,因为除了拷贝对象以外,还需要对象内存空间进行压缩,所以性能较低。
在这里插入图片描述

4、分代收集算法(Generational Collection) 当前商业虚拟机的垃圾收集都采用“分代收集”算法,这种算法并无新的方法,只是根据对象的存活周期的不同将内存划分为几块,一般是把Java堆分为新生代和老年代,这样就可以根据各个年代的特点采用最适当的收集算法。

在新生代中,每次垃圾收集时都发现有大批对象死去,只有少量存活,那就选用复制算法,只需要付出少量存活对象的复制成本就可以完成收集。
而老年代中因为对象存活率高、没有额外空间对它进行分配担保,就必须使用“标记-清理”或“标记-整理”算法来进行回收。

垃圾回收收集器

有 8 种不同的垃圾回收器,它们分别用于不同分代的垃圾回收。
新生代回收器:Serial、ParNew、Parallel Scavenge
老年代回收器:Serial Old、Parallel Old、CMS
整堆回收器:G1、ZGC
两个垃圾回收器之间有连线表示它们可以搭配使用,可选的搭配方案如下:

在这里插入图片描述
搭配使用表:
在这里插入图片描述

串行收集器

1、Serial收集器(用于新生代) 单线程,在进行垃圾收集时必须暂停其他所有的工作线程(“Stop the World”)。虚拟机运行在Client模式下的默认新生代收集器。简单而高效(与其他收集器的单线程比),对于限定单个CPU的环境来说,Serial收集器由于没有线程交互的开销,专心做垃圾收集自然可以获得最高的单线程效率。
特点:

  • Serial收集器是新生代收集器,单线程执行,使用复制算法。
  • 进行垃圾收集时,必须暂停其他所有的工作线程。
  • 对于单个CPU的环境来说,Serial收集器由于没有线程交互的开销,收集效率更高。

配置参数 -XX:+UseSerialGC :年轻串行(Serial 使用复制算法),老年串行(Serial Old,使用标记整理算法)
在这里插入图片描述
也就是说我们需要停止所有线程,但是我们不能随意在某个点暂停,需要在这些点来进行挂起。
Safepoint挂起线程的点主要有:

  • 循环的末尾
  • 方法返回前
  • 调用方法的call之后
  • 抛出异常的位置

2、Serial Old收集器(老年代) 它是Serial收集器的老年代版本,单线程,使用“标记-整理”算法。主要是被Client模式下的虚拟机使用。如果在Server模式下,它还有两大用途:在JDK1.5及之前的版本中与Parallel Scavenge收集器搭配使用;作为CMS 收集器的后备预案,在并发收集发生Concurrent Mode Failure的时候使用。运行过程同Serial收集器。

并行收集器

并行收集器配置参数: -XX:+UseParallelGC 如果这样配置默认启用PS(Parallel Scavenge 收集器)

1、ParNew收集器(新生代) ParNew收集器其实是Serial收集器的多线程版本,在新生代并行,老年代串行,它是许多运行在Server模式下的虚拟机中首选的新生代收集器,因为除了Serial收集器外,目前只有它能与CMS收集器配合工作。
配置参数: -XX:+UseParNewGC
配置参数: -XX:ParallelGCThreads=n 指定线程数
特点:

  • 新生代并行(ParNew),老年代串行(Serial Old)
  • Serial收集器的多线程版本
    在这里插入图片描述
    注意:单CPU性能并不如Serial,因为存在线程交互的开销

2、Parallel Scavenge收集器(“吞吐量优先”收集器)(新生代) 使用复制算法,并行多线程,老年代使用串行收集器,它的独特之处是它的关注点与其他收集器不同,CMS等收集器的关注点是尽可能缩短垃圾收集时用户线程的停顿时间,而Parallel Scavenge收集器的目的则是达到一个可控制的吞吐量(Throughput),即CPU用于运行用户代码的时间与CPU总消耗时间的比值,吞吐量=运行用户代码时间 /(运行用户代码时间+垃圾收集时间),虚拟机总共运行了100分钟,其中垃圾收集花掉1分钟,吞吐量就是99%。 停顿时间越短对于需要与用户交互的程序来说越好,良好的响应速度能提升用户的体验; 高吞吐量可以最高效率地利用CPU时间,尽快地完成程序的运算任务,主要适合在后台运算而不太需要太多交互的任务。
特点

  • 吞吐量优先收集器
  • 新生代使用并行回收收集器,采用复制算法
  • 老年代使用串行收集器
    在这里插入图片描述
    3、Parallel Old收集器(老年代) 它是Parallel Scavenge收集器的老年代版本,多线程,使用“标记-整理”算法。在注重吞吐量及CPU资源敏感的场合,都可以优先考虑Parallel Scavenge+Parallel Old收集器。
    特点
  • Parallel Scavenge收集器的老年代版本,使用多线程和“标记-整理”算法。
  • 在注重吞吐量,CPU资源敏感的场合,都可以优先考虑Parallel Scavenge加Parallel Old收集器。
    配置参数: -XX:+UseParallelOldGC
    在这里插入图片描述
    4、CMS收集器(Concurrent Mark Sweep) 它是一种以获取最短回收停顿时间为目标的收集器。
    配置参数: -XX:+UseConcMarkSweepGC
    尽管CMS收集器采用的是并发回收,但是在其初始标记和重新标记这两个阶段中仍然需要执行“STW”暂停程序中的工作线程,不过暂停时间并不会太长,目前所有的垃圾收集器都做不到完全不需要“STW”,只是尽可能地缩短暂停时间。
    特点:
  • 低延迟:减少STW对用户体验的影响【低延迟要求高】
  • 并发收集:可以同时执行用户线程
  • CMS收集器不能像其他收集器那样等到老年代几乎完全被填满了再进行收集,而是当堆内存使用率
  • 达到某一阈值时,便开始进行回收。
  • CMS收集器的垃圾收集算法采用的是标记-清除算法。
  • 会产生内存碎片,导致并发清除后,用户线程可用的空间不足。
  • CMS收集器对CPU资源非常敏感。
    目前很大一部分Java应用都集中在互联网站或B/S系统的服务端上,这类应用尤其重视服务的响应速度,希望系统停顿时间最短,以给用户带来较好的体验,CMS收集器就非常符合这类应用的需求。
    在这里插入图片描述
    运作过程较复杂,分为4个步骤:
    CMS整个过程比之前的收集器要复杂,整个过程分为4个主要阶段:
  • 初始标记(Initial-Mark)阶段:
    • 本阶段任务:标记出GCRoots能直接关联到的对象。
    • 一旦标记完成之后就会恢复之前被暂停的所有应用线程。
    • 由于直接关联对象比较小,所以这里的速度非常快。
    • 会STW
  • 并发标记(Concurrent-Mark)阶段:
    • 本阶段任务:从GC Roots的直接关联对象遍历整个对象图
    • 这个过程耗时较长
    • 不会STW
  • 重新标记(Remark)阶段:
    • 本阶段任务:修正并发标记期间,因用户程序继续运作产生的新的对象记录
    • 这个阶段的停顿时间通常会比初始标记阶段稍长一些,但也远比并发标记阶段的时间短。
    • 会STW
  • 并发清除(Concurrent-Sweep)阶段:
    • 本阶段任务:清理删除掉标记阶段判断的已经死亡的对象,释放内存空间。
    • 由于不需要移动存活对象,所以这个阶段也是可以与用户线程同时并发的。

5、Garbage First(简称G1)收集器是垃圾收集器技术发展历史上的里程碑式的成果,它开创了收集器面向
局部收集的设计思路和基于Region的内存布局形式。
JDK 8以后G1收集器才被Oracle官方称为“全功能的垃圾收集器”。
G1是一款面向服务端应用的垃圾收集器,大内存企业配置的垃圾收集器大多都是G1。
JDK 9发布之日G1宣告取代Parallel Scavenge加Parallel Old组合,成为服务端模式下的默认垃圾收集器,而CMS则被声明为不推荐使用(Deprecate)。

-XX:+UseG1GC
# 使用 G1 垃圾收集器
-XX:MaxGCPauseMillis=
# 设置期望达到的最大GC停顿时间指标(JVM会尽力实现,但不保证达到),默认值是 200 毫秒。
-XX:G1HeapRegionSize=n
# 设置的 G1 区域的大小。值是 2 的幂,范围是 1 MB 到 32 MB 之间。
# 目标是根据最小的 Java 堆大小划分出约 2048 个区域。
# 默认是堆内存的1/2000。
-XX:ParallelGCThreads=n
# 设置并行垃圾回收线程数,一般将n的值设置为逻辑处理器的数量,建议最多为8。
-XX:ConcGCThreads=n
# 设置并行标记的线程数。将n设置为ParallelGCThreads的1/4左右。
-XX:InitiatingHeapOccupancyPercent=n
# 设置触发标记周期的 Java 堆占用率阈值。默认占用率是整个 Java 堆的 45%。

G1最大堆内存是 32MB*2048=64G ,G1最小堆内存 1MB*2048=2GB ,低于此值建议使用其它收集器。
在这里插入图片描述
特点:

  • 并行与并发:充分利用多核环境下的硬件优势
  • 多代收集:不需要其他收集器配合就能独立管理整个GC堆
  • 空间整合:“标记-整理”算法实现的收集器,局部上基于“复制”算法不会产生内存空间碎片
  • 可预测的停顿:能让使用者明确指定消耗在垃圾收集上的时间。当然,更短的GC时间的代价是回收空间的效率降低。
    G1收集器的运作大致可划分为以下几个步骤:
  1. 初始标记:标记一下GC Roots能直接关联到的对象,需要停顿线程,但耗时很短
  2. 并发标记:是从GC Root开始对堆中对象进行可达性分析,找出存活的对象,这阶段耗时较长,但
    可与用户程序并发执行
  3. 最终标记:修正在并发标记期间因用户程序继续运作而导致标记产生变动的那一部分标记记录
  4. 筛选回收:对各个Region的回收价值和成本进行排序,根据用户所期望的GC停顿时间来制定回收计划
    G1中有三种模式垃圾回收模式,Young GC、Mixed GC 和 Full GC,在不同的条件下被触发。

G1内存划分
G1垃圾收集器相对比其他收集器而言,最大的区别在于它取消了新生代、老年代的物理划分,取而代之
的是将堆划分为若干个区域(Region),这些区域中包含了有逻辑上的新生代、老年代区域。
好处:不用单独的空间对每个代进行设置,不用考虑每个代内存如何分配。
在这里插入图片描述
局部采用复制算法:

  • G1新生代垃圾收集依然采用暂停所有应用线程的方式,将存活对象拷贝到老年代或者Survivor空间
  • G1通过将对象从一个区域复制到另外一个区域,完成了清理工作。 相当于在正常的处理过程中,G1完成了堆的压缩,这样就不会有cms内存碎片问题了。
    Humongous区域:
  • 在G1中,有一种特殊的区域叫Humongous区域如果一个对象占用的空间超过了分区容量50%以上,G1收集器就认为这是一个巨型对象。 这些巨型对象,默认直接会被分配在老年代。
  • 但是,如果是一个短期存在的巨型对象,在分区之间来回拷贝,就会对垃圾收集器造成负面影响。为了解决这个问题,G1划分了Humongous区,它用来专门存放巨型对象。如果一个H区装不下一个巨型对象,那么G1会寻找连续的H分区来存储。
  1. ZGC(Z Garbage Collector)
    Z Garbage Collector,也称为ZGC,在 JDK11 中引入的一种可扩展的低延迟垃圾收集器,在 JDK15 中发布稳定版。
    ZGC的目标:
  • < 1ms 最大暂停时间(jdk < 16 是 10ms,jdk >=16 是 <1ms )
  • 暂停时间不会随着堆、live-set 或 root-set 的大小而增加
  • 适用内存大小从 8MB 到16TB 的堆
    ZGC 具有以下特征:
  • 并发
  • 基于 region
  • 压缩
  • NUMA 感知
  • 使用彩色指针
  • 使用负载屏障
    ZGC 收集器是一款基于 Region 内存布局的, 不设分代的,使用了读屏障、染色指针和内存多重映射等技术来实现可并发的标记-整理算法的,以低延迟为首要目标的一款垃圾收集器。ZGC 的核心是一个并发垃圾收集器,这意味着所有繁重的工作都在Java 线程继续执行的同时完成。这极大地限制了垃圾收集对应用程序响应时间的影响。
-XX:+UseZGC # 启用 ZGC
-Xmx # 设置最大堆内存
-Xlog:gc # 打印 GC日志
-Xlog:gc* # 打印 GC 详细日志
Minor GC 、Major GC和 Full GC 有什么区别?

新生代收集(Minor GC/Young GC):指目标只是新生代的垃圾收集。Minor GC 非常频繁,回收速度比较快。
老年代收集(Major GC/Old GC):指目标只是老年代的垃圾收集, Major GC 一般比 Minor GC慢 10 倍以上。目前只有CMS收集器会有单独收集老年代的行为。另外请注意“Major GC”这个说法现在有点混淆,在不同资料上常有不同所指,需按上下文区分到底是指老年代的收集还是整堆收集。
整堆收集(Full GC):收集整个Java堆和方法区的垃圾收集。
混合收集(Mixed GC):指目标是收集整个新生代以及部分老年代的垃圾收集。目前只有G1收集器会有这种行为。

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

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

相关文章

Python爬虫之自动化测试Selenium#7

爬虫专栏&#xff1a;http://t.csdnimg.cn/WfCSx 前言 在前一章中&#xff0c;我们了解了 Ajax 的分析和抓取方式&#xff0c;这其实也是 JavaScript 动态渲染的页面的一种情形&#xff0c;通过直接分析 Ajax&#xff0c;我们仍然可以借助 requests 或 urllib 来实现数据爬取…

算法练习-赎金信(思路+流程图+代码)

难度参考 难度&#xff1a;中等 分类&#xff1a;哈希表 难度与分类由我所参与的培训课程提供&#xff0c;但需要注意的是&#xff0c;难度与分类仅供参考。且所在课程未提供测试平台&#xff0c;故实现代码主要为自行测试的那种&#xff0c;以下内容均为个人笔记&#xff0c;旨…

Excel TEXT函数格式化日期

一. 基本语法 ⏹Excel 的 TEXT 函数用于将数值或日期格式化为指定的文本格式 TEXT(value, format_text)二. 拼接路径案例 # 将当前单元格日期格式化 "ls -ld /data/jmw/01/"&TEXT(A2,"YYYYMMDD")&""# 此处的日期, 是名称管理器里面定…

自然语言编程系列(四):GPT-4对编程开发的支持

在编程开发领域&#xff0c;GPT-4凭借其强大的自然语言理解和代码生成能力&#xff0c;能够深刻理解开发者的意图&#xff0c;并基于这些需求提供精准的编程指导和解决方案。对于开发者来说&#xff0c;GPT-4能够在代码片段生成、算法思路设计、模块构建和原型实现等方面给予开…

JAVA面试题基础篇

1. 二分查找 要求 能够用自己语言描述二分查找算法 能够手写二分查找代码 能够解答一些变化后的考法 算法描述 前提&#xff1a;有已排序数组 A&#xff08;假设已经做好&#xff09; 定义左边界 L、右边界 R&#xff0c;确定搜索范围&#xff0c;循环执行二分查找&#…

基于Arduino UNO设计一个温控制系统

目录 概述 1 硬件结构 1.1 整体硬件介绍 1.2 硬件连接结构 2 软件设计 2.1 软件功能介绍 2.2 关于Arduino的一些知识点 2.2.1 定时器 2.2.2 PWM 2.3 代码实现 2.3.1 编译工具 2.3.2 详细代码 3 测试 3.1 温度数据监控 3.2 温控测试 概述 本文介绍如何使用Ardui…

精通C语言:打造高效便捷的通讯录管理系统

✨✨ 欢迎大家来到贝蒂大讲堂✨✨ &#x1f388;&#x1f388;养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; 所属专栏&#xff1a;C语言项目 贝蒂的主页&#xff1a;Betty‘s blog 引言 在我们大致学习完C语言之后&#xff0c;我们就可以利用目前所学的知识去…

MATLAB环境下使用二维高分辨时频分析方法提取波状分量

MATLAB环境下使用二维高分辨时频分析方法提取波状分量&#xff08;分离混合地震数据&#xff09;。 为了得到更高的时频分辨率&#xff0c;近年来涌现出了大量的新的时频分析方法。有些以线性和非线性时频分析为基础&#xff0c;有些则另辟蹊径&#xff0c;比如Hilbert-Huang变…

2.12日学习打卡----初学RocketMQ(三)

2.12日学习打卡 目录&#xff1a; 2.12日学习打卡一. RocketMQ高级特性&#xff08;续&#xff09;消息重试延迟消息消息查询 二.RocketMQ应用实战生产端发送同步消息发送异步消息单向发送消息顺序发送消息消费顺序消息全局顺序消息延迟消息事务消息消息查询 一. RocketMQ高级特…

Packet Tracer - Configuring ASA Basic Settings and Firewall Using CLI

Packet Tracer - 使用CLI配置ASA基本设置和防火墙 IP地址表 目标 验证连接并探索ASA设备使用CLI配置ASA的基本设置和接口安全级别使用CLI配置路由、地址转换和检查策略配置DHCP、AAA和SSH服务配置DMZ区域、静态NAT和访问控制列表&#xff08;ACL&#xff09; 场景 您的公司…

grafana配置钉钉告警模版(一)

1、配置钉钉告警模版 创建钉钉告警模版&#xff0c;然后在创建钉钉告警时调用模版。 定义发送内容具体代码 my_text_alert_list 是模版名称后面再配置钉钉告警时需要调用。 {{/* 定义消息体片段 */}} {{ define "my_text_alert_list" }}{{ range . }}告警名称&…

redis为什么使用跳跃表而不是树

Redis中支持五种数据类型中有序集合Sorted Set的底层数据结构使用的跳跃表&#xff0c;为何不使用其他的如平衡二叉树、b树等数据结构呢&#xff1f; 1&#xff0c;redis的设计目标、性能需求&#xff1a; redis是高性能的非关系型&#xff08;NoSQL&#xff09;内存键值数据…

在Postgresql 下安装QGIS

安装QGIS的前提是需要 在windows下安装Postgres&#xff0c;具体可以参考文章&#xff1a; Windows 安装和连接使用 PgSql数据库 安装GIS的具体步骤如下&#xff1a; 一.打开 Application Stack Builder 二.选择默认端口和安装目标 三.选择【Spatial Extensions】 四.选择安装…

链式结构实现队列

链式结构实现队列 1.队列1.1队列的概念及结构1.2队列的实现 2. 队列的各种函数实现3. 队列的全部代码实现 1.队列 1.1队列的概念及结构 队列&#xff1a;只允许在一端进行插入数据操作&#xff0c;在另一端进行删除数据操作的特殊线性表&#xff0c;队列具有先进先出 FIFO(Fi…

【大厂AI课学习笔记】【2.1 人工智能项目开发规划与目标】(5)数据管理

今天学习了数据管理&#xff0c;以及数据管理和数据治理的区别和联系。 数据管理&#xff1a;利用计算机硬件和软件技术对数据进行有效的收集、存储、处理和应用的过程其目的在于充分有效地发挥数据的作用。 实现数据有效管理的关键是数据组织。 数据管理和数据治理的区别&am…

无人驾驶控制算法LQR和MPC的仿真实现

1. LQR控制器 1.1 问题陈述 考虑一个质量为 m m m 的滑块在光滑的一维地面上运动。初始时&#xff0c;滑块的位置和速度均为 0 0 0。我们的目标是设计一个控制器&#xff0c;基于传感器测得的滑块位置 x x x&#xff0c;为滑块提供外力 u u u&#xff0c;使其能够跟随参考…

每日一题——LeetCode1455.检查单词是否为句中其他单词的前缀

方法一 js函数slice() 将字符串按空格符分割为单词数组&#xff0c;记searchWord的长度为n&#xff0c;分割每个单词的前n位看是否和searchWord匹配 var isPrefixOfWord function(sentence, searchWord) {let res sentence.split(" ")for(i 0 ; i < res.lengt…

七天入门大模型 :大模型LLM 训练理论和实战最强总结!

本文对于想入门大模型、面试大模型岗位、大模型实具有很强的指导意义。喜欢记得收藏、关注、点赞 文章目录 技术交流群用通俗易懂方式讲解系列总览介绍预训练范式如何确定自己的模型需要做什么训练&#xff1f;模型推理的一般过程PyTorch 框架设备PyTorch基本训练代码范例Trans…

【复现】cellinx摄像设备 未授权漏洞_50

目录 一.概述 二 .漏洞影响 三.漏洞复现 1. 漏洞一&#xff1a; 四.修复建议&#xff1a; 五. 搜索语法&#xff1a; 六.免责声明 一.概述 cellinx是一家韩国的摄像设备 二 .漏洞影响 通过未授权访问可以创建用户进入后台&#xff0c;可能造成系统功能破坏。 三.漏洞复…

CCF编程能力等级认证GESP—C++8级—20231209

CCF编程能力等级认证GESP—C8级—20231209 单选题&#xff08;每题 2 分&#xff0c;共 30 分&#xff09;判断题&#xff08;每题 2 分&#xff0c;共 20 分&#xff09;编程题 (每题 25 分&#xff0c;共 50 分)奖品分配大量的工作沟通 答案及解析单选题判断题编程题1编程题2…