JVM-2.垃圾回收

news/2024/5/22 5:19:06/文章来源:https://blog.csdn.net/weixin_62427168/article/details/127176891

目录

一、如何判断对象可以回收

1.1 引用计数法

1.2 可达性分析算法

二、五种引用

2.1 强引用

2.2 软引用(SoftReference)

2.3 弱引用(WeakReference)

2.4 虚引用(PhantomReference)

2.5 终结器引用(FinalReference)

三、垃圾回收算法

3.1 标记清除

3.2 标记整理

3.3 复制

四、分代垃圾回收

五、垃圾回收器

5.1 串行

5.2 吞吐量优先(并行) 

5.3 响应时间优先(CMS) 

5.4 G1(Garbage First)

5.5 (重要概念)三色标记/增量更新(CMS)/原始快照(G1)/跨代引用/记忆集/卡表

5.5.1 三色标记与增量更新、原始快照

5.5.2 记忆集、卡表 、跨代引用

六、调优概述


一、如何判断对象可以回收

1.1 引用计数法

         以上图为例,A对象引用了B对象,而B对象也引用了A对象,它们的引用计数都为1.

GC的时候这两个对象都不会被回收。

1.2 可达性分析算法

        -Java 虚拟机中的垃圾回收器采用可达性分析来探索所有存活的对象

        -扫描中的对象,看是否能够沿着 GC Root对象 为起点的引用链找到该对象,找不到,表示可以 回收

        比如我定义了一个ArrayList(List list=new ArrayList()),且添加数据。这时这个ArrayList对象就是root对象,不会被回收。然后令 list=null。此时堆中的ArrayList对象就不是root对象了,它将会被垃圾回收

二、五种引用

2.1 强引用

        只有所有 GC Roots 对象都不通过【强引用】引用该对象,该对象才能被垃圾回收

2.2 软引用(SoftReference)

        仅有软引用引用该对象时,在垃圾回收后内存仍不足时会再次触发垃圾回收,回收软引用 对象。可以配合引用队列释放软引用自身

         示例:

 /*** 演示软引用* -Xmx20m -XX:+PrintGCDetails -verbose:gc*/private static final int _4MB = 4 * 1024 * 1024;public static void main(String[] args) throws IOException {soft();}public static void soft() {// list --> SoftReference --> byte[]List<SoftReference<byte[]>> list = new ArrayList<>();for (int i = 0; i < 5; i++) {SoftReference<byte[]> ref = new SoftReference<>(new byte[_4MB]);System.out.println(ref.get());list.add(ref);System.out.println(list.size());}System.out.println("循环结束:" + list.size());for (SoftReference<byte[]> ref : list) {System.out.println(ref.get());}}
/*** 演示软引用, 配合引用队列*/private static final int _4MB = 4 * 1024 * 1024;public static void main(String[] args) {List<SoftReference<byte[]>> list = new ArrayList<>();// 引用队列ReferenceQueue<byte[]> queue = new ReferenceQueue<>();for (int i = 0; i < 5; i++) {// 关联了引用队列, 当软引用所关联的 byte[]被回收时,软引用自己会加入到 queue 中去SoftReference<byte[]> ref = new SoftReference<>(new byte[_4MB], queue);System.out.println(ref.get());list.add(ref);System.out.println(list.size());}// 从队列中获取无用的 软引用对象,并移除Reference<? extends byte[]> poll = queue.poll();while( poll != null) {list.remove(poll);poll = queue.poll();}System.out.println("===========================");for (SoftReference<byte[]> reference : list) {System.out.println(reference.get());}}

2.3 弱引用(WeakReference)

        仅有弱引用引用该对象时,在垃圾回收时,无论内存是否充足,都会回收弱引用对象。可以配合引用队列释放弱引用自身

/*** 演示弱引用* -Xmx20m -XX:+PrintGCDetails -verbose:gc*/private static final int _4MB = 4 * 1024 * 1024;public static void main(String[] args) {//  list --> WeakReference --> byte[]List<WeakReference<byte[]>> list = new ArrayList<>();for (int i = 0; i < 10; i++) {WeakReference<byte[]> ref = new WeakReference<>(new byte[_4MB]);list.add(ref);for (WeakReference<byte[]> w : list) {System.out.print(w.get()+" ");}System.out.println();}System.out.println("循环结束:" + list.size());}

2.4 虚引用(PhantomReference)

        必须配合引用队列使用,主要配合 ByteBuffer 使用,被引用对象回收时,会将虚引用入队, 由 Reference Handler 线程调用虚引用相关方法释放直接内存

2.5 终结器引用(FinalReference)

        无需手动编码,但其内部配合引用队列使用,在垃圾回收时,终结器引用入队(被引用对象 暂时没有被回收),再由 Finalizer 线程通过终结器引用找到被引用对象并调用它的 finalize 方法,第二次 GC 时才能回收被引用对象

三、垃圾回收算法

3.1 标记清除

                先把那些沿着GC Root 引用链找不到的对象标注出来,然后将这些对象清除(并不是真的把旧数据删除掉,而是相当于标注空闲新数据直接覆盖旧数据) 

        特点

                速度较快

                会造成内存碎片

3.2 标记整理

         先把那些沿着GC Root 引用链找不到的对象标注出来,然后将这些对象清除并进行整理(移动),避免内存碎片

        特点

                速度慢

                没有内存碎片

3.3 复制

        先把那些沿着GC Root 引用链找不到的对象标注出来,然后将还在被引用的对象复制新的内存区域,紧凑排列以避免内存碎片复制完成后把旧区域清除掉,然后把新旧区域位置互换

         特点

                不会有内存碎片

                需要占用双倍内存空间

四、分代垃圾回收

 

        1.对象首先分配在伊甸园区域

        2.新生代空间不足时,触发 minor gc伊甸园幸存区from 存活的对象使用 copy 复制to 中,存活的对象年龄+1并且交换 from、to

        3.minor gc 会引发STW(stop the world)暂停其它用户的线程,等垃圾回收结束,用户线程才恢复运行

        4.当对象寿命超过阈值时,会晋升老年代,最大寿命是15(4bit)

        5.当老年代空间不足,会先尝试触发 minor gc,如果之后空间仍不足,那么触发 full gcSTW的时间更长

        :如果对象大小大于新生代的总大小,则直接存入老年代中。

五、垃圾回收器

5.1 串行

//Serial 用于新生代    SerialOld 用于老年代
-XX:+UseSerialGC = Serial + SerialOld

         只会使用一个CPU或者一条GC线程进行垃圾回收,并且在垃圾回收过程中暂停其他工作线程。使用复制算法实现。

        特点

                单线程

                堆内存较小,适合个人电脑

5.2 吞吐量优先(并行) 

//1.用于新生代的并行垃圾回收    2.用于老年代的并行垃圾回收
-XX:+UseParallelGC ~ -XX:+UseParallelOldGC//自适应的调节策略。我们只要设置最大堆(-Xmx)和MaxGCPauseMillis或GCTimeRadio,收集器会自动调整新生代的大小、伊甸园和存活区的比例、对象进入老年代的年龄...
-XX:+UseAdaptiveSizePolicy//设置吞吐量大小,GC时间占总时间比率.相当于是吞吐量的倒数
-XX:GCTimeRatio=ratio//最大GC停顿时间,回收器根据这个值来决定新生代的大小,如果这个值越小,新生代就会越小,从而收集器就能以较短的时间来进行一次回收。
-XX:MaxGCPauseMillis=ms//设置并行线程数
-XX:ParallelGCThreads=n

        并行多线程回收器,常用于新生代,追求CPU吞吐量的优化,能在较短的时间内完成指定的任务,因此适合不需要太多交互的后台运算。采用复制算法实现。

        吞吐量是指用户线程运行时间CPU总时间的比例,吞吐量越高表示GC时间占比越低,用户体验越好

        特点

                多线程

                堆内存较大,多核 cpu

                让单位时间内,STW 的时间最短,垃圾回收时间占比最低,这样就称吞吐量高

5.3 响应时间优先(CMS) 


-XX:+UseConcMarkSweepGC ~ -XX:+UseParNewGC ~ SerialOld-XX:ParallelGCThreads=n ~ -XX:ConcGCThreads=threads//触发CMS收集器的内存比例
-XX:CMSInitiatingOccupancyFraction=percent//表示在完成多少次CMS之后,进行空间压缩
-XX:+CMSScavengeBeforeRemark//用于在每一次CMS收集器清理垃圾后送一次内存整理。
-XX:+UseCMSCompactAtFullCollection://设置在几次CMS垃圾收集后,触发一次内存整理。整理碎片会stop-the-world.
-XX:CMSFullGCsBeforeCompaction:

        CMS作用于老年代,是一种以获取最短停顿时间为目标的收集器。对于要求服务器响应速度的应用上,这种垃圾回收器非常适合。使用标记-清除算法实现。

         垃圾回收阶段

        1.初始标记(STW)

         标记所有的根对象包括根对象直接引用对象,以及被年轻代中所有存活的对象引用老年代对象

        2.并发标记

        通过遍历第一个阶段(Initial Mark)标记出来的存活对象,继续递归遍历老年代,并标记直接间接到达的所有老年代存活对象。此阶段由于与用户线程并发执行,对象的状态可能会发生变化,如下:

  • 年轻代的对象从年轻代晋升到老年代
  • 有些对象被直接分配到老年代
  • 老年代和年轻代的对象引用关系

        对于这些对象,需要重新标记以防止被遗漏。JVM会通过Card(卡片)的方式将发生改变老年代区域标记为“脏”区,这样后续就只需要扫描这些Dirty Card对象,从而避免扫描整个老年代

    (“当前处理的对象”的一个引用被应用线程断开了,这个部分的对象关系发生了变化,对下一个对象的引用删除)

        2.1 并发预清理

        在并发预清理阶段,将会重新扫描前一个阶段标记的Dirty对象新生代晋升的对象新分配到老年代的对象以及在并发阶段被修改了的对象),并标记被Dirty对象直接间接引用对象,然后清除Card标识

        目的: 标记老年代存活的对象,让最终/重新标记的STW时间尽可能短

        标记目标:

  • 老年代中在并发标记中被标记为“dirty”的card
  • 幸存区(from和to)中引用的老年代对象

         (可以使用-XX:-CMSPrecleaningEnabled 进行关闭,不进行预处理)

        3.重新标记(STW)

        目标: 重新扫描堆中的对象,因为之前的预清理阶段是并发执行的,并发标记的过程中对象及其引用关系还在不断变化中。所以需要有一个stop-the-world的阶段来完成最后的标记工作,重新扫描之前并发处理阶段所有残留更新对象
        扫描范围: 

                新生代对象

                GC Roots

                被标记为“脏”区的对象(大部分已经在预处理阶段被处理过了)

        4.并发清除->并发重置

        JVM在此阶段清理所有未被标记的死亡对象,回收被占用的空间。随后进行并发重置,重新初始化CMS相关数据结构,为下一次GC循环做准备

        CMS的问题

        1.内存碎片问题: 由于CMS使用的是标记-清除算法,这种算法的弊端就是会产生内存碎片,导致大对象无法分配,就会触发Full GC。可以设置参数在Full GC进行碎片整理,但会增加停顿时间

        2.无法处理“浮动垃圾”: 在并发收集阶段时,可能会出现下面的情况:当用户线程创建了一个对象年轻代放不下,直接放到老年代;年轻代对象晋升老年代。由于存在这种情况,因此CMS垃圾收集器必须要预留一部分空间用户线程(需要更大的堆空间),不能等到老年代满了才收集。

        出现这些问题会导致“并发失败” / “晋升失败”,此时会临时启用Serial Old(串行)收集器(Full GC)来重新进行老年代收集,这会导致停顿时间更长。。。

5.4 G1(Garbage First)

        G1(Garbage First)是一个横跨新生代老年代的垃圾收集器。

        实际上,它已经打乱了新生代老年代堆结构,直接将分成多个区域(rigion)。每个区域都可以充当 Eden 区、Survivor 区或者老年代中的一个。G1 会将超过 region 50% 大小的对象(在应用中,通常是 byte 或 char 数组)归类为 Humongous 对象,并放置在相应的 region 中。

        逻辑上,Humongous region 算是老年代的一部分,因为复制这样的大对象是很昂贵的操作,并不适合新生代 GC 的复制算法。

        region 大小大对象很难保证一致,这会导致空间的浪费。上面示意图中有的区域是 Humongous 颜色,但没有用名称标记,这是为了表示,特别大的对象是可能占用超过一个 region 的。并且region 太小不合适会使得分配大对象时更难找到连续空间,这是一个长久存在的情况。

        G1采用的是标记 - 整理算法,而且和 CMS 一样都能够在应用程序运行过程中并发地进行垃圾回收。 G1 能够针对每个细分的区域来进行垃圾回收。在选择进行垃圾回收的区域时,它会优先回收死亡对象较多的区域。这也是 G1 名字的由来。

        G1的垃圾回收阶段

        Young GC -> Young GC+Concurrent Mark -> Mixed GC

1.新生代GC

        存活的对象被复制或者移动到一个或多个survivor区域,如果满足老化阈值,这些对象就会被晋升老年代。年轻代GC是stop-the-world的一个事件,所有的应用程序线程必须停止,等待这个操作完成。

2.新生代GC+并发标记

        在 Young GC 时会进行 GC Root初始标记(STW)

        当老年代占用堆空间比例达到阈值时,进行并发标记(不会 STW)。

 2.1 根区域扫描

        由于初始标记必然会伴随一次新生代GC,所以在初始化标记后,eden被清空,并且存活对象被移到survivor区。在这个阶段,将扫描survivor直接可达老年代区域,并标记这些直接可达的对象。 这个过程是可以和应用程序并发执行的。

 2.2 并发标记

        和CMS类似,并发标记将会扫描并查找整个存活对象,并做好标记。这是一个并发过程,并且这个过程可以被一次新生代GC打断

        在并发标记过程中,应用程序依然运行,因此标记结果可能需要修正,所以在此阶段对上一次标记进行补充。在G1中,这个过程使用SATB(Snapshot-At-The-Begining)算法完成,即G1会在标记之初存活对象创建一个快照,这个快照有助于加快重新标记的速度

        SATB 利用 write barrier 将所有即将被删除的引用关系的旧引用记录下来。这些记录存在一个队列中,供重新标记时使用。

3.混合回收

        这个阶段会对 伊甸园、幸存区、老年代 进行全面垃圾回收。混合回收会被执行多次,直到回收了足够多的内存空间。在并发标记周期中,虽有部分对象回收,但是回收的比例是非常的。在并发标记周期后,G1已经明确知道哪些区域含有比较多的垃圾对象,在混合回收阶段,就可以专门针对这些区域进行回收。当然G1会优先回收垃圾比例较高的区域。然后,它会触发一次新生代GC

3.1 重新标记

        和CMS一样,重新扫描之前并发处理阶段所有残留更新对象。重新标记也会STW。
3.2 独占清理

        顾名思义,这个阶段会引起STW。它将计算各个区域的存活对象GC回收比例并进行排序,识别可供混合回收的区域。在这个阶段,还会更新记忆集。该阶段给出了需要被混合回收的区域并进行了标记,在混合回收阶段,需要这些信息。
3.3 并发清理

        识别并清理完全空闲的区域。它是并发的清理,不会引起STW

        必要时的Full GC

        和CMS类似,并发收集让应用程序和GC线程交替工作,因此在特别繁忙的情况下无可避免的会发生回收过程中内存不足的情况,当遇到这种情况,G1会转入Full GC 进行回收。

        1.在Mix GC之前,老年代就被填满-并发模式失效

        2.在进行GC的时候没有足够的内存供存活对象晋升对象使用-晋升失败

        3.进行新生代垃圾收集时,幸存区老年代中没有足够的空间容纳所有幸存对象-疏散失败

5.5 (重要概念)三色标记/增量更新(CMS)/原始快照(G1)/跨代引用/记忆集/卡表

5.5.1 三色标记与增量更新、原始快照

我们把遍历对象图过程中遇到的对象,按“是否访问过”这个条件标记成以下三种颜色:

  • 白色:尚未访问过。(扔掉
  • 黑色:本对象已访问过,而且本对象 引用到 的其他对象 也全部访问过了。(保留
  • 灰色:本对象已访问过,但是本对象 引用到 的其他对象 尚未全部访问完。全部访问后,会转换为黑色。(待定

并发标记期间,对象间的引用可能发生变化多标漏标的情况就有可能发生。

  • 浮动垃圾(多标):将原本应该被清除的对象,误标记为存活对象。后果是垃圾回收不彻底,不过影响不大,可以在下个周期被回收;
  • 对象消失(漏标):将原本应该存活的对象,误标记为需要清理的对象。后果很严重,影响程序运行,是不可容忍的。

我们必须解决漏标的问题。而漏标必须要同时满足以下两个条件:

  1. 赋值器插入了一条或者多条从黑色对象到白色对象的新引用
  2. 赋值器删除了全部从灰色对象到该白色对象的直接或间接引用

为了破坏上面两个条件中的一个,有如下方案:

  • 增量更新:Incremental Update。(在新增一条引用时,将该记录保存)
  • 原始快照:Snapshot At The Beginning,SATB。(当灰色对象要删除指向白色对象的引用关系时,将这个要删除的引用记录下来)

现代追踪式可达性分析)的垃圾回收器几乎都借鉴了三色标记的算法思想,如:

  • CMS:写屏障 + 增量更新
  • G1:写屏障 + SATB(原始快照)

5.5.2 为什么G1 使用SATB,而不使用CMS的增量更新?

        增量更新:黑色对象新增一条指向白色对象的引用,那么要进行深入扫描白色对象及它的引用对象

        原始快照:灰色对象删除了一条指向白色对象的引用,实际上就产生了浮动垃圾,好处是不需要像 CMS 那样 remark,再走一遍 root trace 这种相当耗时的流程。

        SATB相对增量更新效率会高(当然SATB可能造成更多的浮动垃圾),因为不需要在重新标记阶段再次深度扫描被删除引用对象,而CMS对增量引用的根对象会做深度扫描。

        G1因为很多对象都位于不同region,CMS就一块老年代区域,重新深度扫描对象的话G1的代价会比CMS高,所以G1选择SATB不深度扫描对象,只是简单标记,等到下一轮GC深度扫描

5.5.2 记忆集、卡表 、跨代引用

        跨代引用

        所谓跨代引用就是老年代的对象引用新生代的对象,或者新生代的对象引用老年代的对象。那对于这种情况我们的GC在进行扫描的时候不可能直接把我们的整个堆都扫描完,那这样效率也太低了。所以这时候就需要开辟了一小块空间,维护这种引用,而不必让GC扫描整个堆区域。这片空间叫 dirty card queue

        记忆集

        记忆集也叫rememberSet,垃圾收集器在新生代中建立了记忆集这样的数据结构,用来避免把整个老年代加入到GC ROOTS扫描范围中。对于记忆集来说,我们可以理解为他是一个抽象类,那么具体实现它的方法将由子类去完成。

        卡表

        卡表(Card Table)是一种对记忆集具体实现。主要定义了记忆集的记录精度与堆内存的映射关系等。卡表中的每一个元素都对应着一块特定大小的内存块,这个内存块我们称之为卡页(card page),当存在跨代引用的时候,它会将卡页标记dirty。那么JVM对于卡页的维护也是通过写屏障的方式。

六、调优概述

        1.确定调优的目标-内存响应速度吞吐量

                响应速度调优的重点是在短的时间内快速响应

                高吞吐量应用更关心的是如何尽可能快地完成整个任务不考虑快速响应用户请求

        2.新生代

        GC在该区域的执行频率高于其他区域。

        -如果新生代的大小太小,则会执行多次GC;如果太大,则只执行full GC(老年代装不下),这可能需要很长时间才能完成。Oracle建议将新生代的大小保持在总堆大小25%~50%

        -使幸存区大到能保留【当前活跃对象+需要晋升对象

        -晋升阈值配置得当,让长时间存活对象尽快晋升

        3.老年代(CMS为例)

                -老年代越大越好

                -调整触发CMS的阈值,至少能容得下浮动垃圾,防止直接退化成 Serial Old GC

                -调整触发Full GC 的阈值

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

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

相关文章

07 hook学习01

hook学习01Hooks理解useStateuseEffect自定义hook函数Hooks理解 react组件分为类组件和函数组件 函数组件是一个更加匹配react的设计理念UI f(data)&#xff0c;利于逻辑拆分与重用的组件表达形式&#xff0c;而之前的函数组件是不可以有自己的状态的&#xff0c;为了能让函…

第二章:微服务架构构建

第二章&#xff1a;微服务架构构建 2.1&#xff1a;IDEA新建project工作空间 父工程步骤 New Project 聚合总父工程名字 Maven版本选择 字符编码 注解生效激活 Java编译版本选择8 父工程pom文件 <?xml version"1.0" encoding"UTF-8"?&g…

谷粒商城 nacos

下载nacos&#xff1a;https://github.com/alibaba/nacos/releases启动 startup.cmd -m standalone依赖 <dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></depende…

(附源码)计算机毕业设计ssm大学生健康系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

Vue学习第37天——.sync修饰符、$attrs和$listeners属性的使用场景和案例

目录一、.sync修饰符作用使用场景使用方法案例.sync修饰符的优势二、$attrs作用使用场景使用方法案例$attrs注意点三、$listeners作用使用场景使用方法案例$listeners注意点一、.sync修饰符 作用 之前组件进行双向绑定时&#xff0c;需要通过proos进行父传子&#xff0c;再通…

Python 实现DNS查询放大攻击

查询放大攻击的原理是&#xff0c;通过网络中存在的DNS服务器资源&#xff0c;对目标主机发起的拒绝服务攻击&#xff0c;其原理是伪造源地址为被攻击目标的地址&#xff0c;向DNS递归服务器发起查询请求&#xff0c;此时由于源IP是伪造的&#xff0c;固在DNS服务器回包的时候&…

六自由度模拟飞行C++教程

六自由度模拟飞行C教程 带引导、控制和导航 课程英文名&#xff1a;Flight Dynamics in Six Degrees of Freedom 此视频教程共14.5小时&#xff0c;中英双语字幕&#xff0c;画质清晰无水印&#xff0c;源码附件全 下载地址 百度网盘地址&#xff1a;https://pan.baidu.com…

云原生|kubernetes|k8s集群测试时的一些基本操作

前言&#xff1a; kubernetes集群作为一个能够明显提升生产力的工具&#xff0c;还是需要多多练习一些基本操作的&#xff0c;我说的基本操作主要是针对基本的测试环节而不是生产环境下的操作。例如&#xff0c;在生产环境下用命令行启动一个pod并通过NodePort把这个pod运行的…

前端性能优化 - 华为面试题

前端性能优化面试题 前端性能优化总体来说分为 &#xff1a;优化请求、打包优化、代码优化 。 文章目录前端性能优化面试题Ⅰ、如何优化请求图片方面① 精灵图 ② 小图标 Base64③ 图片懒加载④ 图标库 采用 svg请求内容方面 ① 减少请求内容大小 ②更改请求方式③ 防抖节流④…

PyCharm 的初始设置

PyCharm 的官方网站地址&#xff1a;https://www.jetbrains.com/pycharm/ 教育版下载地址&#xff1a;https://www.jetbrains.com/pycharm-edu/download/#sectionlinux 专业版下载地址&#xff1a;https://www.jetbrains.com/pycharm/download/#sectionlinux 1、恢复 PyCharm …

视觉里程计

2D-2D&#xff1a;对极几何 C0, C1分别是两个位置中相机的光心&#xff0c;也就是针孔相机模型中的针孔 P是空间中的一个三维点&#xff0c;p0, p1分别是P点在不同成像平面上对应的像素点 C0-C1-P-p0-p1他们都是在同一个平面上的&#xff0c;你可以想象C0-C1-P组成的平面是一个…

5_循环神经网络 RNN

RNN什么是RNN序列数据处理序列数据的神经网络RNN弊端LSTM什么是RNN 循环神经网络RNN用于语言分析, 序列化数据。 序列数据 有一组序列数据 data 0,1,2,3. 在当预测 result0 的时候,我们基于的是 data0, 同样在预测其他数据的时候, 我们也都只单单基于单个的数据. 每次使用的…

零基础小白复现Java 若依项目

若依项目1 概述2 环境配置3 打包项目4 导入项目5 配置项目数据库连接&#xff0c;数据源配置6 然后运行代码1 概述 RuoYi-Vue 是一个 Java EE 企业级快速开发平台&#xff0c;基于经典技术组合&#xff08;Spring Boot、Spring Security、MyBatis、Jwt、Vue&#xff09;&#x…

redis常用命令,redis入门,启动redis,启动哨兵

Redis服务器默认使用6379号端口&#xff0c;通过–port参数可以自定义端口号&#xff1a; 正确停止Redis的方式应该是向Redis发送SHUTDOWN命令&#xff0c;方法为&#xff1a; Redis可以妥善处理SIGTERM信号&#xff0c;所以使用kill Redis进程的PID也可以正常停止Redis&#…

yolov3 spp讲解

1、yolov3 spp各个版本对比 yolov3 spp版本主要在以下几个方面做了改进&#xff1a;(1)、Mosaic图像增强&#xff1b;&#xff08;2&#xff09;、SPP模块&#xff1b;&#xff08;3&#xff09;、CIOU Loss ;&#xff08;4&#xff09;、Focal Loss . 2、Mosaic图像增强 Mosai…

聊一聊ShardingSphere的读写分离

什么是 ShardingSphere Apache ShardingSphere 是一款分布式的数据库生态系统&#xff0c; 可以将任意数据库转换为分布式数据库&#xff0c;并通过数据分片、弹性伸缩、加密等能力对原有数据库进行增强。 ShardingSphere-JDBC ShardingSphere-JDBC 定位为轻量级 Java 框架&…

【 uniapp 】打包Android的apk(原生APP-云打包),及发布测试

前言&#xff1a; 跨端(小程序、Android、IOS)项目开发好了&#xff0c;我们如何去利用 uniapp 的云打包去打包 apk 文件&#xff0c;然后上传测试呢&#xff1f;今天我们一起来学习一下&#xff0c;一步一步如何实现&#xff01; 目录 一、 打包 Android &#xff0c;生成apk…

猿创征文|TiDB架构解析和注意事项

TiDB 简介 TiDB是一款开源的分布式HTAP数据库&#xff0c;同事支持TP&#xff08;Transactional Processing&#xff09;的在线事务处理&#xff0c;也支持AP&#xff08;Analytical Processing&#xff09;的在线分析处理。 实际使用下来的感受&#xff1a;TP场景的高并发确实…

修建金字塔-第12届蓝桥杯Scratch省赛3真题第4题

[导读]&#xff1a;超平老师计划推出Scratch蓝桥杯真题解析100讲&#xff0c;这是超平老师解读Scratch蓝桥真题系列的第42讲。 第12届蓝桥杯青少年组省赛分两次进行&#xff0c;这是2021年4月24日举行的第二次省赛考试初级组&#xff0c;形式为在线考试。Scratch分为初级组和中…

Redis常用数据类型:String、List、Set(待补充。。。)

文章目录Redis键&#xff08;key&#xff09;字符串&#xff08;String&#xff09;常用命令String的数据结构列表&#xff08;List&#xff09;常用命令List的数据结构集合&#xff08;Set&#xff09;常用命令Set的数据结构Redis键&#xff08;key&#xff09; 基本命令 key…