【JVM】垃圾回收机制

【JVM】垃圾回收机制

文章目录

  • 【JVM】垃圾回收机制
    • 1. 方法区的回收
    • 2. 堆的回收
      • 2.1 引用计数法
      • 2.2 可达性分析算法
    • 3. 对象引用
      • 3.1 强引用
      • 3.2 软引用
      • 3.3 弱引用
      • 3.4 虚引用和终结器引用
    • 4. 垃圾回收算法
      • 4.1 标记清除算法
      • 4.2 复制算法
      • 4.3 标记整理算法
      • 4.4 分代垃圾回收算法
    • 5. 垃圾回收器
      • 5.1 年轻代-Serial垃圾回收器
      • 5.2 老年代-SerialOld垃圾回收器
      • 5.3 年轻代-ParNew垃圾回收器
      • 5.4 老年代-CMS(Concurrent Mark Sweep)垃圾回收器
      • 5.5 年轻代-Parallel Scavenge垃圾回收器
      • 5.6 老年代-Parallel Old垃圾回收器
      • 5.7 G1垃圾回收器
      • 5.8 总结

1. 方法区的回收

方法区中能够回收的内容主要是不再使用的类。我们知道类的生命周期有七个部分,最后一个就是卸载

判定一个类可以被卸载,需要同时满足三个条件:

  1. 此类的所有实例对象都已经被回收了,也就是说在堆中已经不存在该类的实例对象以及子类对象了。

    Class<?> clazz = loader.loadClass("com.zhj.A");
    Object o = clazz.newInstance();
    o = null;
    
  2. 加载该类的类加载器已经被回收了。

    URLClassLoader loader = new URLClassLoader(new URL[]{new URL("file:D:\\lib\\")});
    loader = null;
    
  3. 该类对应的 java.lang.Class 对象没有在任何地方被引用。

    Class<?> clazz = loader.loadClass("com.zhj.A");
    clazz = null;
    

我们知道,项目当中我们自己创建的类都是由应用程序类加载器来进行加载的,而应用程序类加载器是不会被置为null的,也就是说这个类无法被卸载。

但是在一些特定场景下还是会出现类加载器被置为null的情况,主要在如 OSGi、JSP 的热部署等应用场景中。 每个jsp文件对应一个唯一的类加载器,当一个jsp文件修改了,就直接卸载这个jsp类 加载器。重新创建类加载器,重新加载jsp文件。


2. 堆的回收

2.1 引用计数法

引用计数法:Java中的对象是否能被回收,是根据对象是否被引用来决定的。如果对象被引用了,说明该对象还在使用,不允许被回收。引用计数法会为每个对象维护一个引用计数器,当对象被引用时加1,取消引用时减1。

优点:

  1. 实现简单。

缺点:

  1. 每次引用和取消引用都需要维护计数器,对系统性能会有一定的影响。
  2. 存在循环引用,A,B对象相互引用时会出现对象无法回收的问题,造成内存泄漏

2.2 可达性分析算法

可达性分析算法:Java使用的是可达性分析算法来判断对象是否可以被回收。可达性分析将对象分为两类:垃圾回收的根对象(GC Root)和普通对象,对象与对象之间存在引用关系。

A到B再到C和D,形成了一个引用链,可达性分析算法指的是如果从某个到GC Root对象是可达的,对象就不可被回收。

image-20231029002756786

也就是说,如果对象A到对象B的引用链断了,那么对象B,C,D都可以被垃圾回收了。

那么哪些对象可以被称之为GC Root呢?

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

main线程作为虚拟机栈中引用的对象可以作为GC Root,那么可以通过它去判断对象是否可以回收:

image-20231029003045990

当 a1 b1 置为 null 时,也就表示栈内存中 a1 到堆内存中 A的实例对象的引用链断了,b1 到堆内存中 B的实例对象的引用链断了,所以线程对象根据引用链到不了AB的实例对象了,所以AB的实例对象就可以被垃圾回收了。


3. 对象引用

3.1 强引用

可达性分析算法中描述的对象引用,一般指的是强引用,即是GCRoot对象对普通对象有引用关系,只要这层关系存在,普通对象就不会被回收。


3.2 软引用

软引用相对于强引用是一种比较弱的引用关系,如果一个对象只有软引用关联到它,当程序内存不足时,就会将软 引用中的数据进行回收

在JDK 1.2版之后提供了SoftReference类来实现软引用,软引用常用于缓存中

软引用的执行过程如下:

  1. 将对象使用软引用包装起来。

    byte[] bytes = new byte[1024 * 1024 * 100];
    //将100m的数据放入软引用中
    SoftReference<byte[]> softReference = new SoftReference<byte[]>(bytes);
    
  2. 内存不足时,虚拟机尝试垃圾回收。

  3. 如果垃圾回收仍不能解决内存不足的问题,则回收软引用中的对象。

  4. 如果内存依旧不足,则抛出OOM异常。

软引用中的对象如果在内存不足时回收,SoftReference对象本身也需要被回收,我们又如何在适当时机将它回收呢?

SoftReference提供了一套队列机制:

  1. 软引用创建时,通过构造器传入引用队列。
  2. 在软引用中包含的对象被回收时,将该SoftReference对象本身放入引用队列。
  3. 通过代码遍历引用队列,将SoftReference的强引用删除。

3.3 弱引用

弱引用的整体机制和软引用基本一致,区别在于弱引用包含的对象在垃圾回收时,不管内存够不够都会直接被回收。

在JDK 1.2版之后提供了WeakReference类来实现弱引用,弱引用主要在ThreadLocal中使用。 弱引用对象本身也可以使用引用队列进行回收。
在这里插入图片描述

3.4 虚引用和终结器引用

这两种引用在常规开发中是不会使用的。

  • 虚引用也叫幽灵引用/幻影引用,不能通过虚引用对象获取到包含的对象。虚引用唯一的用途是当对象被垃圾回收器回收时可以接收到对应的通知。Java中使用PhantomReference实现了虚引用,直接内存中为了及时知道 直接内存对象不再使用,从而回收内存,使用了虚引用来实现。
  • 终结器引用指的是在对象需要被回收时,终结器引用会关联对象并放置在Finalizer类中的引用队列中,在稍后由一条由FinalizerThread线程从队列中获取对象,然后执行对象的finalize方法,在对象第二次被回收时,该 对象才真正的被回收。在这个过程中可以在finalize方法中再将自身对象使用强引用关联上,但是不建议这样做。

4. 垃圾回收算法

垃圾回收要做的两件事:

  1. 找到内存中存活的对象
  2. 释放不再存活的对象的内存,使得程序能再次利用这部分空间。

Java垃圾回收过程通过单独的GC线程来完成,不管使用哪一种GC算法,都会有部分阶段需要停止所有的用户线程。这个过程被称之为 Stop The World 简称STW,如果STW时间过长则会影响用户的使用。

垃圾回收算法的评价标准

判断垃圾回收算法是否优秀,可从以下三个方面来考虑:

  1. 吞吐量:吞吐量指的是 CPU 用于执行用户代码的时间与 CPU 总执行时间的比值,即吞吐量 = 执行用户代码时间 / (执行用户代码时间 + GC时间)。吞吐量数值越高,垃圾回收的效率就越高。

    image-20231029160229833

  2. 最大暂停时间:最大暂停时间指的是所有在垃圾回收过程中的STW时间最大值。比如如下的图中,黄色部分的STW就是最 大暂停时间,显而易见上面的图比下面的图拥有更少的最大暂停时间。最大暂停时间越短,用户使用系统时受到的影响就越短。

    image-20231029160325018

  3. 堆使用率:不同垃圾回收算法,对堆内存的使用方式是不同的。比如标记清除算法,可以使用完整的堆内存。而复制算 法会将堆内存一分为二,每次只能使用一半内存。从堆使用效率上来说,标记清除算法要优于复制算法。

上面提到的三种评价标准:吞吐量,最大暂停时间,堆使用率不可兼得。

一般来说,堆内存越大,最大暂停时间就越长,想要减少最大暂停时间,就会降低吞吐量。所以说没有最好的算法,只有最适合不同场景的算法。


4.1 标记清除算法

标记清除算法的核心思想分为两个阶段:

  1. 标记阶段:使用可达性分析算法从GC Root通过引用链标记所有存活对象。
  2. 清除阶段:从内存中删除没有被标记的对象。

优点:

  1. 实现简单,只需在标记阶段给每个对象维护标志位,在清除阶段删除对象即可。

缺点:

  1. 造成内存碎片。由于内存是连续的,所以在对象被删除之后,内存中会出现很多细小的可用内存单元。如果我们需要的是一 个比较大的空间,很有可能这些内存单元的大小过小无法进行分配。

  2. 分配速度慢。由于内存碎片的存在, 需要维护一个空闲链表,极有可能发生每次需要遍历到链表的最后才能获得合适的内存空间。

    image-20231029162122377


4.2 复制算法

复制算法的核心思想是:

  1. 准备两块空间From空间和To空间,每次在对象分配阶段,只使用From空间。
  2. 在垃圾回收阶段,将From中存活对象复制到To空间。
  3. 将两块空间名字互换。

优点:

  1. 吞吐量高
  2. 不会发生内存碎片,复制算法在复制之后就会将对象按顺序放 入To空间中,所以对象以外的区域都是可 用空间,不存在碎片化内存空间。

缺点:

  1. 内存使用率低,每次只能让一半的内存空间给创建对象使用。

4.3 标记整理算法

标记整理算法核心思想分为两个阶段:

  1. 标记阶段:使用可达性分析算法从GC Root通过引用链标记所有存活对象。
  2. 整理阶段:将存活对象移动到堆的一端,从内存中删除没有存活的对象。

优点:

  1. 内存使用率高:整个堆内存都可以使用,不会像复 制算法只能使用半个堆内存
  2. 不会发生碎片化:在整理阶段可以将对象往内存的一侧进行移动,剩下的空间都是可以分配对象的有效空间
  3. 整理阶段的效率不高

4.4 分代垃圾回收算法

现代优秀的垃圾回收算法,会将上述描述的算法组合使用,其中应用最广的就是分代垃圾回收算法。

分代垃圾回收将整个内存区域划分为年轻代老年代。年轻代用来存放存活时间较短的对象,老年代用来存放存活时间较长的对象。

年轻代由有三部分组成:

  1. Eden区/伊甸园区
  2. S0幸存区
  3. S1幸存区

调整内存区域大小

根据以下虚拟机参数,调整堆的大小并观察结果。注意加上 -XX:+UseSerialGC
在这里插入图片描述


分代垃圾回收流程:

  1. 分代回收时,创建出来的对象首先被放入Eden伊甸园区。

  2. 随着对象在Eden区越来越多,如果EDen区满了,新创建的对象无法放入,就会触发年轻代的GC,称之为Minor GC或者Young GC。Minor GC会把需要Eden中区中和From需要回收的对象回收,把没有回收的对象放入To区。

    image-20231029170300385

  3. 接下来,S0会变成To区,S1变成From区。当Eden区满时再往里放入对象,依然会发生Minor GC。此时回收Eden区和S1(From)中的对象,并把eden和from区中剩余对象放入S0(To)。(注意:每次 Minor GC都会为对象记录他的年龄,初始值为0,每次GC完加1)

    image-20231029170319879

  4. 如果Minor GC后对象的年龄达到阈值(最大15,默认值和垃圾回收器有关),对象就会被晋升至老年代。

  5. 当老年代中空间不足导致无法放入新对象时,会先尝试Minor GC(因为不是只有年龄到达15的对象会放入老年代,如果新生代中存放了很多年龄不大的兑现导致新生代中满了,年轻对象也会放入老年代),如果还是不足,就会触发Full GC,Full GC会对整个堆进行垃圾回收。如果Full GC依然无法回收掉老年代的对象,那么当对象继续放入老年代时就会抛出OOM异常。


5. 垃圾回收器

  • 系统中的大部分对象,都是创建出来之后很快就不再使用可以被回收的,比如用户获取订单数据,订单数据返回给用户之后就可以释放了。
  • 老年代中会存放长期存活的对象,比如Spring的大部分bean对象,在程序启动之后就不会被回收了。
  • 在虚拟机的默认设置中,新生代大小要远小于老年代的大小。

分代GC算法将堆分成年轻代和老年代的主要原因有:

  1. 可以通过调整年轻代和老年代的比例来适应不同类型的应用程序,提高内存的利用率和性能。
  2. 新生代和老年代使用不同的垃圾回收算法,新生代一般选择复制算法,老年代可以选择标记清除标记整理算法,由程序员来选择灵活度较高。
  3. 分代的设计中允许只回收新生代(Minor GC),如果能满足对象分配的要求就不需要对整个堆进行回收(Full GC),STW时间就会减少。

image-20231029203122358


垃圾回收器是垃圾回收算法的具体实现。

由于垃圾回收器分为年轻代和老年代,除了G1之外其他垃圾回收器必须成对组合使用。

image-20231029203350149


5.1 年轻代-Serial垃圾回收器

Serial是一种单线程串行回收年轻代的垃圾回收器。使用复制算法

image-20231029203727651

  • 优点:单CPU处理器下吞吐量非常出色。
  • 缺点:多CPU下吞吐量不如其他垃圾回收器,堆如果偏大会让用户线程处于长时间的等待。
  • 适用场景:Java编写的客户端程序或者硬件配置有限的场景。

5.2 老年代-SerialOld垃圾回收器

SerialOld是Serial垃圾回收器的老年代版本,采用单线程串行垃圾回收,使用标记整理算法。使用 -XX:+UseSerialGC 指令则年轻代和老年代都使用串行回收器。

image-20231029214029719

  • 优点:单CPU处理器下吞吐量非常出色
  • 缺点:多CPU下吞吐量不如其他垃圾回收器,堆如果偏大会让用户线程处于长时间的等待
  • 适用场景:与Serial垃圾回收器搭配使用, 或者在CMS特殊情况下使用

5.3 年轻代-ParNew垃圾回收器

ParNew垃圾回收器本质上是对Serial在多CPU下的优化,使用多线程进行垃圾回收,使用复制算法-XX:+UseParNewGC 年轻代使用ParNew垃圾回收器,老年代使用SerialOld垃圾回收器。

image-20231029213955115

  • 优点:多CPU处理器下停顿时间较短
  • 缺点:吞吐量和停顿时间不如G1,所以在JDK9后不建议使用
  • 适用场景:JDK8及之前的版本中,与CMS老年代垃圾回收器搭配使用。

5.4 老年代-CMS(Concurrent Mark Sweep)垃圾回收器

CMS垃圾回收器关注的是系统的暂停时间,允许用户线程和垃圾回收线程在某些步骤中同时执行,减少了用户线程的等待时间。使用标记清除算法-XX:+UseConcMarkSweepGC

  • 优点:系统由于垃圾回收出现的停顿时间较短,用户体验好。
  • 缺点
    1. 内存碎片问题。
    2. 退化问题。
    3. 浮动垃圾问题。
  • 适用场景:大型的互联网系统中用户请求数 据量大、频率高的场景 比如订单接口、商品接口等。

CMS的执行步骤:

  1. 初始标记,用极短的时间标记出GC Root能直接关联到的对象。
  2. 并发标记。标记所有对象,用户线程不需要暂停。
  3. 重新标记,由于并发标记阶段有些对象会发生变化,存在错标,漏标等情况,需要重新标记。
  4. 并发清理,清理死亡的对象,用户线程不需要暂停。

image-20231029214511634

CMS的缺点:

  1. CMS使用了标记清除算法,在垃圾回收结束之后会出现大量的内存碎片,CMS会在Full GC时进行碎片的整理。这样会导致用户线程暂停,可以使用 -XX:CMSFullGCsBeforeCompaction=N 参数调整N(默认为0)次Full GC之后再整理。
  2. 无法处理在并发清理过程中产生的”浮动垃圾“(在并发清理阶段用户线程产生的垃圾不能立即回收,需要等到下次并发清理),不能做到完全的垃圾回收。
  3. 如果老年代内存不足无法分配对象,CMS就会退化成Serial Old单线程回收老年代。

5.5 年轻代-Parallel Scavenge垃圾回收器

Parallel Scavenge垃圾回收器是jdk8默认的年轻代垃圾回收器,多线程并行回收,关注的是系统的吞吐量。具备自动调整堆内存大小的特点。使用复制算法。

image-20231029220359014

  • 优点:吞吐量高,而且手动可控。 为了提高吞吐量,虚拟机会动态调整堆的参数。
  • 缺点:不能保证单次的停顿时间。
  • 适用场景:后台任务,不需要与用户交互,并且容易产生大量的对象 比如:大数据的处理,大文件导出

5.6 老年代-Parallel Old垃圾回收器

Parallel Old是为Parallel Scavenge收集器设计的老年代版本,利用多线程并发收集。适用标记整理算法

参数:-XX:+UseParallelGC 或者 -XX:+UseParallelOldGC 可以使用Parallel Scavenge + Parallel Old这种组合。

image-20231029220359014

  • **优点:**并发收集,在多核CPU下 效率较高
  • 缺点:暂停时间会比较长
  • 适用场景:与Parallel Scavenge配套使用

Parallel Scavenge允许手动设置最大暂停时间和吞吐量。Oracle官方建议在使用这个组合时,不要设置堆内存的最大值,垃圾回收器会根据最大暂停时间和吞吐量 自动调整内存大小。

  • 最大暂停时间-XX:MaxGCPauseMillis=n 设置每次垃圾回收时的最大停顿毫秒数
  • 吞吐量-XX:GCTimeRatio=n 设置吞吐量为n(用户线程执行时间 = n/n + 1)
  • 自动调整内存大小-XX:+UseAdaptiveSizePolicy 设置 可以让垃圾回收器根据吞吐量和最大停顿的毫秒数自动调整内存大小

5.7 G1垃圾回收器

参数1: -XX:+UseG1GC 打开G1的开关,JDK9之后默认不需要打开。参数2:-XX:MaxGCPauseMillis=毫秒值 最大暂停的时间。使用复制算法

image-20231029231626784

  • 优点:对比较大的堆如超过6G的堆回收时,延迟可控,不会产生内存碎片,并发标记的SATB算法效率高
  • 缺点:JDK8之前还不够成熟
  • 适用场景:JDK8最新版本,JDK9之后建议默认适用。

JDK9之后默认的垃圾回收器是G1(Garbage First)垃圾回收器。

Parallel Scavenge关注吞吐量,允许用户设置最大暂停时间,但是会减少年轻代可用空间的大小。

CMS关注暂停时间,但是吞吐量方面会下降。

而G1设计目标就是将上述两种垃圾回收器的优点融合(JDK9之后建议使用G1垃圾回收器):

  1. 支持巨大的堆空间回收,并有较高的吞吐量。
  2. 支持多CPU并行垃圾回收。
  3. 允许用户设置最大暂停时间。

在G1出现之前的垃圾回收器,内存结构一般是连续的,如下图所示:

image-20231029223932246

而在G1中整个堆会被划分成多个大小相等的区域,称之为区Region,区域不要求是连续的。分为Eden、Survivor、 Old区。Region的大小通过堆空间大小/2048计算得到,也可以通过参数 -XX:G1HeapRegionSize=32m 指定(其中32m指定region大小为32M),Region size必须是2的指数幂,取值范围从1M到32M。

image-20231029224047037

G1垃圾回收有两种方式:

  1. 年轻代回收(Young GC)
  2. 混合回收(Mixed GC)

年轻代回收(Young GC),回收Eden和Survivor区中不用的对象。会导致STW,G1中可以通过参数 -XX:MaxGCPauseMillis=n (默认为200)设置每次垃圾回收时的最大暂停时间毫秒数,G1垃圾回收器会尽可能的保证暂停时间。

年轻代回收执行流程:

  1. 新创建的对象会存放在Eden区。当G1判断年轻代区不足(max默认60%),无法分配对象时需要回收时会执行 Young GC。
  2. 标记出Eden和Survivor区域中的存活对象
  3. 根据配置的最大暂停时间选择某些区域将存活对象复制到一个新的Survivor区中(年龄+1),清空这些区域。

image-20231029224532556

G1在进行Young GC的过程中会去记录每次垃圾回收时每个Eden区和Survivor区的平均耗时,以作为下次回收时的参考依据。这样就可以根据配置的最大暂停时间计算出本次回收时最多能回收多少个Region区域了。

比如 -XX:MaxGCPauseMillis=n(默认200),每个Region回收耗时40ms,那么这次回收最多只能回收4个Region。

  1. 后续Young GC时与之前相同,只不过Survivor区中存活对象会被搬运到另一个Suvivor区。
  2. 当某个存活对象的年龄到达阈值(默认15),将被放入老年代。

image-20231029225751332

  1. 部分对象如果大小超过Region的一半,会直接放入老年代,这类老年代被称为 Humongous 区。比如堆内存是4G,每个Region是2M,只要一个大对象超过了1M就被放入Humongous区,如果对象过大会横跨多个Region。

image-20231029225949084

  1. 多次回收之后,会出现很多Old老年代区,此时总堆占有率达到阈值时( -XX:InitiatingHeapOccupancyPercent 默认45%)会触发混合回收MixedGC,回收所有年轻代和部分老年代的对象以及大对象区。采用复制算法来完成。

image-20231029230405549


**混合回收(Mixed GC)**分为:初始标记(initial mark),并发标记(concurrent mark),最终标记(remark或者Finalize Marking),并发清理(cleanup)。

G1对老年代的清理会选择存活度最低的区域来进行回收,这样可以保证回收效率最高,这也是G1(Garbage first)名称的由来。

image-20231029230907252

最后清理阶段使用复制算法,不会产生内存碎片。

注意:如果清理过程中发现没有足够的空Region存放转移的对象,会出现Full GC。单线程执行标记-整理算法, 此时会导致用户线程的暂停。所以尽量保证应该用的堆内存有一定多余的空间。


5.8 总结

JDK8及之前:

  • ParNew + CMS (关注暂停时间)
  • PS + PO(关注吞吐量)
  • G1(JDK8之前不建议,较大堆并且关注暂停时间)

JDK9之后:

  • G1(默认)

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

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

相关文章

202310-宏基组学物种分析工具-MetaPhlAn4安装和使用方法-Anaconda3- centos9 stream

MetaPhlAn 4是一种基于DNA序列的微生物组分析工具&#xff0c;它能够从宏基因组测序数据中识别和分离微生物的组成。以下是安装和使用MetaPhlAn 4的步骤&#xff1a; 安装MetaPhlAn 4&#xff1a; 裸机环境&#xff0c;手动安装 1. 安装依赖项&#xff1a; MetaPhlAn 4需要…

FreeRTOS_信号量之二值信号量

目录 1. 信号量简介 2. 二值信号量 2.1 二值信号量简介 2.1.1 二值信号量无效 2.1.2 中断释放信号量 2.1.3 任务获取信号量成功 2.1.4 任务再次进入阻塞态 2.2 创建二值信号量 2.2.1 vSemaphoreCreateBinary() 2.2.2 xSemaphoreCreateBinary() 2.2.3 xSemaphoreCrea…

算法的时间复杂度及空间复杂度

目录 一、前言 二、时间复杂度 1.时间复杂度定义 2.时间复杂度描述方法 三、实例代码 实例1&#xff08;取影响最大的项&#xff09; 实例2&#xff08;舍去系数&#xff09; 实例3&#xff08;不确定大小关系的用max函数取最大&#xff09; 实例4&#xff08;常数次的…

编译运行windows+OpenMVG+OpenMVS+vs2017

安装vcpkg过程需要翻墙&#xff01;&#xff01;&#xff01; github下载代码 git clone https://github.com/microsoft/vcpkg git clone https://github.com/cdcseacave/VCG.git git clone https://github.com/cdcseacave/openMVS.git src安装vcpkg包 cd .\vcpkg .\bootstr…

HC32M120时钟配置内部时钟为48MHz

HC32M120 时钟比较简单&#xff0c;外部时钟最高只支持20MHz&#xff0c;并且没有PLL&#xff0c;想要48M时钟只能通过内部HRC时钟配置&#xff0c;经过一番研究发现可以直接在hc32m120_icg.h中配置上电时钟为48MHz即可&#xff0c;如果不配置直接使用CLK_HRCInit(CLK_HRC_ON, …

AcWing92 递归实现指数型枚举:输出1~n的所有子集

题目 从 1∼ n n n 这 n n n 个整数中随机选取任意多个&#xff0c;输出所有可能的选择方案。 输入格式 输入一个整数 n n n。 输出格式 每行输出一种方案。 同一行内的数必须升序排列&#xff0c;相邻两个数用恰好 1 个空格隔开。 对于没有选任何数的方案&#xff0c…

“第五十五天”

定点数&#xff1a; 原码的乘法&#xff1a; 乘法的符号位是单独处理的&#xff08;通过对被乘数和乘数的符号位进行异或实现&#xff09;&#xff0c;数值位去绝对值进行运算。这里的乘法实际上是通过多次加法实现的。 这里被乘数是放在x寄存器&#xff0c;乘数放在MQ寄存器…

【SpringBoot】Docker部署

docker部署是主流的部署方式&#xff0c;极大的方便了开发部署环境&#xff0c;保持了环境的统一&#xff0c;也是实现自动化部署的前提。 1 项目的目录结构 package: 点击打包&#xff0c;生成 xxx-SNAPSHOT.jar target目录: 打包生成目录&#xff0c;生成的jar存放位置Docke…

三种前端埋点方式

什么是埋点 埋点是数据采集领域&#xff08;尤其是用户行为数据采集领域&#xff09;的术语&#xff0c;指的是针对特定用户行为或事件进行捕获、处理和发送的相关技术及其实施过程。比如用户某个icon点击次数、观看某个视频的时长等等。 我们可以知道埋点实际上是对特定事件或…

【网络安全】Seeker内网穿透追踪定位

Seeker追踪定位对方精确位置 前言一、kali安装二、seeker定位1、ngrok平台注册2、获取一次性邮箱地址3、ngrok平台登录4、ngrok下载5、ngrok令牌授权6、seeker下载7、运行seeker定位8、运行隧道开启监听9、伪装链接10、用户点击&#xff08;获取定位成功&#xff09;11、利用经…

10.30 知识总结(标签分类、css介绍等)

一、 标签的分类 1.1 单标签 img br hr <img /> 1.2 双标签 a h p div <a></a> 1.3 按照标签属性分类 1.3.1 块儿标签 即自己独自占一行 h1-h6 p div 1.3.2 行内(内联)标签 即自身文本有多大就占多大 a span u i b s 二、 标签的嵌套 标签之间是可以互相…

iTransformer: INVERTED TRANSFORMERS ARE EFFECTIVE FOR TIME SERIES FORECASTING

#论文题目&#xff1a;ITRANSFORMER: INVERTED TRANSFORMERS ARE EFFECTIVE FOR TIME SERIES FORECASTING #论文地址&#xff1a;https://arxiv.org/abs/2310.06625 #论文源码开源地址&#xff1a;https://github.com/thuml/Time-Series-Library #论文所属会议&#xff1a;Mach…

基于单片机的智能清洁小车设计—控制系统设计

收藏和点赞&#xff0c;您的关注是我创作的动力 文章目录 概要 一、研究的主要内容和目标二、总体方案设计2.1智能清洁小车的硬件系统组成2.2智能清洁小车的硬件结构图 三、 小车结构设计5.1基本布局和功能分析5.2小车二维及三维图小车三维图&#xff1a; 四、 原理图程序 五、…

在CentOS 7中手工打造和运行xml文件配置的Servlet,然后使用curl、浏览器、telnet等三种工具各自测试

下载Openjdk并配置环境变量 https://jdk.java.net/java-se-ri/11-MR2是官网下载Openjdk 11的地方。 sudo wget https://download.java.net/openjdk/jdk11.0.0.1/ri/openjdk-11.0.0.1_linux-x64_bin.tar.gz下载openjdk 11。 sudo mkdir -p /usr/openjdk11创建目录&#xff…

UE5 日记(人物连招:蒙太奇动画通知(含视频链接))

教程https://www.youtube.com/watch?vsWpENaVGj2M&listPLiSlOaRBfgkcPAhYpGps16PT_9f28amXi&index10&ppiAQB 相关蓝图 连招逻辑 动画通知类 逻辑分析 1.用户输入 已搭载战斗系统模块,可以收到输入指令 2.连击 第一次攻击&#xff1a; 第一次攻击&#xff0c;…

Qt中设置鼠标透明度的应用及示例

Qt中设置鼠标透明度的应用及示例 介绍设置鼠标透明度的方法应用场景遮罩层可视化效果 结论 介绍 Qt是一个功能强大的跨平台应用程序开发框架&#xff0c;可以用于开发各种类型的应用程序。在Qt中&#xff0c;我们可以设置鼠标的透明度&#xff0c;即将鼠标事件传递给下方的控件…

vulnhub momentum 靶机复盘

环境配置 到学校了 原来的桥接配置要改 这里记录几个点备忘 1.virtualbox 桥接 未指定 重新安装驱动VBoxNetLwf.inf 2.配置完靶机启动失败 手动安装VBoxNetLwf.inf 不要用virtualbox自带的netlwfinstall 3.配置完nmap扫不到 rw init/bin/bash 进去看看网卡配置 信息收集…

Docker底层原理:UFS的使用

文章目录 前言检查系统是否支持OverlayFS准备两个目录加载OverlayFS模块创建OverlayFS使用OverlayFS卸载OverlayFS 前言 Linux中常用的联合文件系统有OverlayFS和Aufs(Another Union File System), OverlayFS是Linux内核自带的联合文件系统, 而Aufs则是第三方提供的联合文件系…

C语言_字符串和内存函数

文章目录 前言一. strlen二. strcpy三.strcat四. strcmp &#xff08;字符串比较&#xff09;五. strncpy六. strncmp七. strstr八. strtok九 . strerror perror十. 字符分类函数十一. memcpy (内存拷贝&#xff09;十二. memmove(可以重叠拷贝 也可以实现不重叠的内存拷贝) 前…

VC++程序崩溃时,使用Visual Studio静态分析dump文件

Window环境下的C程序如果发生异常崩溃&#xff0c;首先会和客户联系&#xff0c;让帮忙取特定目录下的dump文件和log文件来分析崩溃的原因。不过发生崩溃的话&#xff0c;从log一般分析不出特定原因&#xff0c;这时候dump文件就起作用了。可以通过Visual Studio和Windbg来静态…