当前位置: 首页 > news >正文

JVM基础篇:垃圾回收

目录

1.前言

1.1C/C++的内存管理

1.2Java的内存管理

2.方法区的回收

3.堆回收

3.1引用计数法和可达性分析法

3.2五种对象引用

强引用

软引用

弱引用

虚引用

终结器引用

3.3垃圾回收算法评价标准

①吞吐量

②最大暂停时间

③堆使用效率

3.4垃圾回收算法

①标记清除算法

②复制算法

③标记整理算法

④分代GC(重点)

调整内存区域的大小

对象回收的执行流程

对象晋升的特殊情况

为什么分代GC算法要把堆分成年轻代和老年代?

3.5垃圾回收器

垃圾回收器的组合关系

年轻代-Serial垃圾回收器

老年代-SerialOld垃圾回收器

年轻代-ParNew垃圾回收器

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

年轻代-Parallel Scavenge垃圾回收器

老年代-Parallel Old垃圾回收器

G1垃圾回收器(重点)

G1垃圾回收器 – 内存结构

年轻代回收(Young GC)

混合回收(Mixed GC)

FULL GC

优缺点


1.前言

1.1C/C++的内存管理

  • 在C/C++这类没有自动垃圾回收机制的语言中,一个对象如果不再使用,需要手动释放,否则就会出现内存泄漏。我们称这种释放对象的过程为垃圾回收,而需要程序员编写代码进行回收的方式为手动回收
  • 内存泄漏指的是不再使用的对象在系统中未被回收,内存泄漏的积累可能会导致内存溢出

1.2Java的内存管理

Java中为了简化对象的释放,引入了自动的垃圾回收(Garbage Collection简称GC)机制。通过垃圾回收器来对不再使用的对象完成自动的回收,垃圾回收器主要负责对上的内存进行回收。其他很多现代语言比如C#、Python、Go都拥有自己的垃圾回收器。

2.方法区的回收

方法区中能回收的内容主要就是不再使用的类。

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

  1. 此类所有实例对象都已经被回收,在堆中不存在任何该类的实例对象以及子类对象。
  2. 加载该类的类加载器已经被回收。
  3. 该类对应的 java.lang.Class 对象没有在任何地方被引用。

由于我们自己编写的类是由应用程序类加载器加载的,而这个加载器在运行过程中是不会被回收的,所以我们自己编写的类只要被加载就不会被回收

3.堆回收

3.1引用计数法和可达性分析法

引用计数法

引用计数法会为每个对象维护一个引用计数器,当对象被引用时加1,取消引用时减1。引用计数法的优点是实现简单,但是它也存在缺点,主要有两点:

  1. 每次引用和取消引用都需要维护计数器,对系统性能会有一定的影响
  2. 存在循环引用问题,所谓循环引用就是当A引用B,B同时引用A时会出现对象无法回收的问题。

补充:查看垃圾回收日志

  • 如果想要查看垃圾回收的信息,可以使用-verbose:gc参数。
  • 语法: -verbose:gc

可达性分析算法

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

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

哪些对象被称之为GC Root对象呢?

  • 线程Thread对象,它会关联线程栈帧中的方法参数、局部变量等。
  • 系统类加载器加载的java.lang.Class对象,它会关联类中的静态变量。
  • 监视器对象,用来保存同步锁synchronized关键字持有的对象。
  • 本地方法调用时使用的全局对象(一般不用关注)。

3.2五种对象引用

强引用

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

软引用

  • 软引用相对于强引用是一种比较弱的引用关系,如果一个对象只有软引用关联到它,当程序内存不足时,就会将软引用中的数据进行回收。
  • 在JDK 1.2版之后提供了SoftReference类来实现软引用,软引用常用于缓存中。

  • 内存不足时,虚拟机尝试进行垃圾回收。
  • 如果垃圾回收仍不能解决内存不足的问题,回收软引用中的对象。
  • 如果依然内存不足,虚拟机会抛出OutOfMemory异常。

创建软引用对象

  • 将对象使用软引用包装起来
  • 继承SoftReference类的方式来实现软引用

软引用中的对象如果在内存不足时回收,SoftReference对象本身也需要被回收。如何知道哪些SoftReference对 象需要回收呢?

SoftReference提供了一套队列机制:

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

引用队列里存放的是所有已经被回收数据的软引用对象

弱引用

  • 弱引用的整体机制和软引用基本一致,区别在于弱引用包含的对象在垃圾回收时,不管内存够不够都会直接被回收。
  • 在JDK 1.2版之后提供了WeakReference类来实现弱引用,弱引用主要在ThreadLocal中使用。
  • 弱引用对象本身也可以使用引用队列进行回收。

虚引用

虚引用也叫幽灵引用/幻影引用,不能通过虚引用对象获取到包含的对象。虚引用唯一的用途是当对象被垃圾回收器回收时可以接收到对应的通知。Java中使用PhantomReference实现了虚引用,直接内存中为了及时知道直接内存对象不再使用,从而回收内存,使用了虚引用来实现

终结器引用

  • 最后这两种引用在常规开发中是不会使用的。
  • 终结器引用指的是在对象需要被回收时,终结器引用会关联对象并放置在Finalizer类中的引用队列中,在稍后由一条由FinalizerThread线程从队列中获取对象,然后执行对象的finalize方法,在对象第二次被回收时,该对象才真正的被回收。在这个过程中可以在finalize方法中再将自身对象使用强引用关联上,但是不建议这样做。

3.3垃圾回收算法评价标准

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

①吞吐量

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

②最大暂停时间

最大暂停时间指的是所有在垃圾回收过程中的STW时间最大值。最大暂停时间越短,用户使用系统时受到的影响就越短。

③堆使用效率

不同垃圾回收算法,对堆内存的使用方式是不同的。比如标记清除算法,可以使用完整的堆内存。而复制算法会将堆内存一分为二,每次只能使用一半内存。

  • 上述三种评价标准:堆使用效率、吞吐量,以及最大暂停时间不可兼得。
  • 一般来说,堆内存越大,需要回收的对象可能就越多,最大暂停时间就越长。
  • 如果想要减少最大暂停时间,可能会将很长的一次的回收拆分成多次,这样会做很多重复的准备工作,就会降低吞吐量

垃圾回收算法没有最好与最坏,不同的垃圾回收算法,适用于不同的场景。

3.4垃圾回收算法

①标记清除算法

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

  1. 标记阶段,将所有存活的对象进行标记。Java中使用可达性分析算法,从GC Root开始通过引用链遍历出所有存活对象。
  2. 清除阶段,从内存中删除没有被标记也就是非存活对象。

标记清除算法的优缺点

  • 优点:实现简单,只需要在第一阶段给每个对象维护标志位,第二阶段删除对象即可。
  • 缺点:
    • ①碎片化问题:由于内存是连续的,所以在对象被删除之后,内存中会出现很多细小的可用内存单元。如果我们需要的是一个比较大的空间,很有可能这些内存单元的大小过小无法进行分配。
    • ②分配速度慢。由于内存碎片的存在,需要维护一个空闲链表,极有可能发生每次需要遍历到链表的最后才能获得合适的内存空间。

②复制算法

复制算法的核心思想是:

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

演示过程

  1. 将堆内存分割成两块From空间 To空间,对象分配阶段,创建对象。
  2. GC阶段开始,将GC Root搬运到To空间
  3. 将GC Root关联的对象,搬运到To空间
  4. 清理From空间,并把名称互换

复制算法的优缺点

  • 优点:
    • ①吞吐量高:复制算法只需要遍历一次存活对象 复制到To空间即可,比标记-整理 算法少了一次遍历的过程,因而性 能较好,但是不如标记-清除算法,因为标记清除算法不需要进行对象的移动
    • ②不会产生碎片化空间:复制算法在复制之后就会将对象按顺序放 入To空间中,所以对象以外的区域都是可 用空间,不存在碎片化内存空间。
  • 缺点:
    • 内存使用效率低:每次只能让一半的内存空间来为创建对象使用

③标记整理算法

标记整理算法也叫标记压缩算法,是对标记清理算法中容易产生内存碎片问题的一种解决方案。

核心思想分为两个阶段:

  1. 标记阶段,将所有存活的对象进行标记。Java中使用可达性分析算法,从GC Root开始通过引用链遍历出所有存活对象。
  2. 整理阶段,将存活对象移动到堆的一端。清理掉存活对象的内存空间。

标记整理算法的优缺点

  • 优点:
    • ①内存使用效率高:整个堆内存都可以使用,不会像复制算法只能使用半个堆内存
    • ②不会发生碎片化:在整理阶段可以将对象往内存的一侧进行移动,剩下的空间都是可以分配对象的有效空间
  • 缺点:
    • 整理阶段的效率不高:整理算法有很多种,比如Lisp2整理算法需要对整个堆中的对象搜索3次,整体性能不佳。可以通过TwoFinger、表格算法、ImmixGC等高 效的整理算法优化此阶段的性能

④分代GC(重点)

  • 现代优秀的垃圾回收算法,会将上述描述的垃圾回收算法组合进行使用,其中应用最广的就是分代垃圾回收算法(Generational GC)。
  • 分代垃圾回收将整个内存区域划分为年轻代老年代年轻代又划分为Eden区(伊甸园区)幸存者区(包括S0和S1)

调整内存区域的大小

对象回收的执行流程
  1. 分代回收时,创建出来的对象,首先会被放入Eden伊甸园区。
  2. 随着对象在Eden区越来越多,如果Eden区满,新创建的对象已经无法放入,就会触发年轻代的GC,称为 Minor GC或者Young GC。
  3. Minor GC会把需要eden中和From需要回收的对象回收,把没有回收的对象放入To区。
  4. 接下来,S0会变成To区,S1变成From区。当eden区满时再往里放入对象,依然会发生Minor GC。 此时会回收eden区和S1(from)中的对象,并把eden和from区中剩余的对象放入S0,接下来,S0会变成From区,S1变成To区。 注意:每次Minor GC中都会为对象记录他的年龄,初始值为0,每次GC完加1。
  5. 如果Minor GC后对象的年龄达到阈值(最大15,默认值和垃圾回收器有关),对象就会被晋升至老年代。
  6. 当老年代中空间不足,无法放入新的对象时,先尝试minor gc如果还是不足,就会触发Full GC,Full GC会对整个堆进行垃圾回收。 如果Full GC依然无法回收掉老年代的对象,那么当对象继续放入老年代时,就会抛出Out Of Memory异常。
对象晋升的特殊情况

当 Eden 区没有足够空间进行分配时,虚拟机将发起一次 Minor GC。GC 期间虚拟机又发现对象无法存入 Survivor(幸存者) 空间,所以只好通过 分配担保机制 把新生代的对象提前转移到老年代中去,而此时该对象的年龄则不需要达到阈值

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

3.5垃圾回收器

如果说收集算法是内存回收的方法论,那么垃圾收集器就是内存回收的具体实现。

虽然我们对各个收集器进行比较,但并非要挑选出一个最好的收集器。因为直到现在为止还没有最好的垃圾收集器出现,更加没有万能的垃圾收集器,我们能做的就是根据具体应用场景选择适合自己的垃圾收集器

JDK 默认垃圾收集器:

  • JDK 8:Parallel Scavenge(新生代)+ Parallel Old(老年代)
  • JDK 9 ~ JDK20: G1

垃圾回收器的组合关系

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

具体的关系图如下:

  • 添加JVM参数-XX:+UseSerialGC,新生代、老年代都将使用串行回收器
  • 添加JVM参数-XX:+UseParNewGC 新生代使用ParNew回收器, 老年代使用串行回收器(JDK9废弃)
  • 添加JVM参数-XX:+UseParNewGC XX:+UseConcMarkSweepGC 新生代使用ParNew回收器,老年代使用CMS回收器。
  • 添加JVM参数-XX:+UseParallelGC 或 -XX:+UseParallelOldGC可以使用 Parallel Scavenge + Parallel Old这种组合。
  • 添加JVM参数-XX:+UseG1GC 打开G1的开关, JDK9之后默认不需要打开

年轻代-Serial垃圾回收器

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

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

老年代-SerialOld垃圾回收器

SerialOld是Serial垃圾回收器的老年代版本,采用单线程串行回收,回收算法采用标记-整理算法

  • 优点和缺点与Serial垃圾回收器一样
  • 适用场景:①与Serial垃圾回收器搭配使用;②作为 CMS 收集器的后备方案

添加JVM参数-XX:+UseSerialGC,新生代、老年代都将使用串行回收器。

年轻代-ParNew垃圾回收器

ParNew垃圾回收器本质上是对Serial在多 CPU下的优化,使用多线程进行垃圾回收。 

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

添加JVM参数-XX:+UseParNewGC 新生代使用ParNew回收器,老年代使用串行回收器。

添加JVM参数-XX:+UseParNewGC XX:+UseConcMarkSweepGC 新生代使用ParNew回收器,老年代使用CMS回收器。

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

CMS垃圾回收器关注的是系统的暂停时间,允许用户线程和垃圾回收线程在某些步骤中同时执行,减少了用户线程的等待时间。

从名字中的Mark Sweep这两个词可以看出,CMS 收集器是一种 “标记-清除”算法实现的,它的运作过程相比于前面几种垃圾收集器来说更加复杂一些。整个过程分为四个步骤:

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

  • 优点:并发收集、低停顿
  • 缺点:
    • ①CMS使用了标记-清除算法,在垃圾收集结束之后会出现大量的内存碎片,当有不足以提供整块连续的空间给新对象/晋升为老年代对象时又会触发FullGC。
    • ②无法处理浮动垃圾:在执行"并发清理"步骤时,用户线程也会同时产生一部分可回收对象,但是这部分可回收对象只能在下次执行清理是才会被回收。如果在清理过程中预留给用户线程的内存不足就会出现"Concurrent Mode Failure",一旦出现此错误时便会切换到SerialOld收集方式
    • ③CMS收集器对CPU资源非常敏感,在并发阶段虽然不会导致用户线程停顿,但是会因为占用了一部分CPU资源,如果在CPU资源不足的情况下应用会有明显的卡顿。

年轻代-Parallel Scavenge垃圾回收器

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

Parallel Scavenge允许手动设置最大暂停时间和吞吐量。

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

设置最大暂停时间

-XX:MaxGCPauseMillis=n 设置每次垃圾回收时的最大停顿毫秒数。当我们把最大暂停时间设置更小时,Parallel Scavenge回收器会将堆内存减小,以减少最大停顿时间。

设置吞吐量

-XX:GCTimeRatio=n 设置吞吐量为n(用户线 程执行时间 = n/n + 1)

自动调整内存大小(默认开启)

-XX:+UseAdaptiveSizePolicy设置可以让垃圾回收器根据吞吐量和最大停顿的毫秒数自动调整内存大小

注:比较短的最大暂停时间和比较高的吞吐量其实是矛盾的,所以如果同时设置了这两者,Parallel Scavenge回收器可能只能尽力达成其中一个目标。建议多次测试,将两者调成合理的值。

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

老年代-Parallel Old垃圾回收器

Parallel Old是为Parallel Scavenge收集器设计的老年代版本,利用多线程并发收集。

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

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

G1垃圾回收器(重点)

G1 (Garbage-First) 是一款面向服务器的垃圾收集器,主要针对配备多颗处理器及大容量内存的机器. 以极高概率满足 GC 停顿时间要求的同时,还具备高吞吐量性能特征.

JDK9及之后默认的垃圾回收器是G1(Garbage First)垃圾回收器。JDK9及之后强烈建议使用G1垃圾回收器。

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

而G1设计目标就是将上述两种垃圾回收器的优点融合:

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

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

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

年轻代回收(Young 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),清空这些区域。

  4. 后续Young GC时与之前相同,只不过Survivor区中存活对象会被搬运到另一个Survivor区。
  5. 当某个存活对象的年龄到达阈值(默认15),将被放入老年代。
  6. 特殊情况:部分对象如果大小超过Region的一半,会直接放入老年代,这类老年代被称为Humongous区。比如堆内存是 4G,每个Region是2M,只要一个大对象超过了1M就被放入Humongous区,如果对象过大会横跨多个Region。
  7. 多次回收之后,会出现很多Old老年代区,此时老年代占整堆比达到阈值时(-XX:InitiatingHeapOccupancyPercent 默认45%)会触发混合回收MixedGC。回收所有年轻代和部分老年代的对象以及大对象区。采用复制算法来完成。

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

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

混合回收(Mixed GC)
  • 混合回收分为:初始标记、并发标记、最终标记、并发清理
  • G1对老年代的清理会选择存活度(存活的对象数/总对象数)最低的区域来进行回收,这样可以保证回收效率最高,这也是G1(Garbage first)名称的由来。

FULL GC

G1垃圾回收器的Full GC会在以下条件下触发

  • 从年轻代分区拷贝存活对象时,无法找到可用的空闲Region(分区)
  • 从老年代分区转移存活对象时,无法找到可用的空闲Region(分区)
  • 分配巨型对象时在老年代无法找到足够的连续分区

Full GC会单线程执行标记-整理算法, 此时会导致用户线程的暂停。所以尽量保证应该用的堆内存有一定多余的空间。

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

相关文章:

JVM基础篇:垃圾回收

目录 1.前言 1.1C/C的内存管理 1.2Java的内存管理 2.方法区的回收 3.堆回收 3.1引用计数法和可达性分析法 3.2五种对象引用 强引用 软引用 弱引用 虚引用 终结器引用 3.3垃圾回收算法评价标准 ①吞吐量 ②最大暂停时间 ③堆使用效率 3.4垃圾回收算法 ①标记清…...

蓝桥杯ACwing习题

题目 :https://www.acwing.com/problem/content/4409/ 解析 :根据题目我们可以知道 问的是方案数 那么首先就想到了 dp 仔细想一下 发现类似于蒙德里安的梦想那道状态压缩的题 , 所以我们先考虑怎么定义 f[i][j] f[i][j] 表示的是 已经放了…...

vue发送请求携带token,拼接url地址下载文件

封装请求 ,该请求为普通的get请求 该请求返回值为: 请求成功之后拼接URL地址下载文件 代码块 downTemplateRequest(activeKeys.value).then((res) > {let url http://47.169.168.99:18888/media/${res.data.name};var elink document.createElemen…...

【PTA-C语言】编程练习3 - 循环结构Ⅱ

如果代码存在问题,麻烦大家指正 ~ ~有帮助麻烦点个赞 ~ ~ 编程练习3 - 循环结构(9~15) 7-9 特殊a串数列求和(分数 15)7-10 穷举法搬运砖块问题(分数 15)7-11 数字金字塔(分数 15&…...

Google Chrome 下载 (离线版)

1 访问网址 Google Chrome 网络浏览器 2 点击 下载Chrome 3 直接运行 ChromeStandaloneSetup64.exe 其他: ####################### 谷歌浏览器 (Google Chrome) 最新版离线安装包下载 https://www.iplaysoft.com/tools/chrome/#google_vignette Google Chrome …...

2023年GopherChina大会-核心PPT资料下载

一、峰会简介 自 Go 语言诞生以来,中国便是其应用最早和最广的国家之一,根据 Jetbrains 在 2021 年初做的调查报告,总体来说目前大概有 110 万专业的开发者 选择 Go 作为其主要开发语言。就其全球分布而言, 居住在亚洲的开发者最多&#xff…...

从源代码出发,Jenkins 任务排队时间过长问题的解决过程

最近开发了一个部署相关的工具,使用 Jenkins 来构建应用。Jenkins 的任务从模板中创建而来。每次部署时,通过 Jenkins API 来触发构建任务。在线上运行时发现,通过 API 触发的 Jenkins 任务总是会时不时在队列中等待较长的时间。某些情况下的…...

openssl 生成CA及相关证书

实验环境:ubuntu18.04-desktop 获取openssl.cnf配置文件 # 这个返回的路径,不一定被使用了(经测试,ubuntu18下的openssl似乎未加载任何配置文件) openssl version -d生成私钥文件(pem) # 生成私钥 # genrsa&#xf…...

App测试之App日志收集及adb常用命令

文章目录 前言一、adb是什么1.APP测试收集手机日志常用的工具2.adb下载与安装3.ADT/SDK/ADB是什么4.adb连接真机 二、adb常用命令三、android系统日志文件1.logcat日志文件2.logcat日志文件分析 四、分析crash & ANR 日志1.发生crash如何分析2.发生ANR如何分析 总结扩展&am…...

【Java面试——并发基础、并发关键字】

3.1 并发基础 Java 并发 - 理论基础Java 并发 - 线程基础 多线程的出现是要解决什么问题的? 本质什么? CPU、内存、I/O 设备的速度是有极大差异的,为了合理利用 CPU 的高性能,平衡这三者的速度差异,计算机体系结构、操作系统、编译程序都…...

如何使用 Java 在Excel中创建下拉列表

下拉列表(下拉框)可以确保用户仅从预先给定的选项中进行选择,这样不仅能减少数据输入错误,还能节省时间提高效率。在MS Excel中,我们可以通过 “数据验证” 提供的选项来创建下拉列表,但如果要在Java程序中…...

Python安装步骤介绍

本文将介绍Python安装的详细步骤如下: 下载 python安装 python配置环境变量(安装时勾选配置环境变量的则无需此步骤) 一、python下载 官网:Download Python | Python.org 根据电脑位数下载所需的版本 二、Python安装 1.打开安…...

学习80min快速了解大型语言模型(ChatGPT使用)笔记

学习李宏毅:80min快速了解大型语言模型(ChatGPT使用)笔记 链接:https://www.youtube.com/watch?vwG8-IUtqu-s 1、创建一个属于自己的GPT 目前,GPT4具备一个功能,Create a GPT。利用这个功能可以创建一个…...

SQL错题集1

1.找出选修课程成绩最差的选课记录 注: 聚合函数只能用在group by和()括号中 找最值可用排序order bylimit 1 2. 查询选修成绩 合格的课程 超过2门的 学生编号 3.删除姓名为"LiMing"的学生信息 注: 删除一整行信息&…...

uniapp运行到安卓基座app/img标签不显示

img是html中的标签,他也是一个单标签 image属于服务器控件,是个双标签 问题:uniapp运行到app安卓基座后图片无法显示 原因:自己使用了img标签,而且输入路径无提示,img标签导致图片不显示 解决&#xff…...

vscode非常好用的扩展插件

1、Code Spell Checker: 帮助我们检查单词是否拼写错误,检查规则遵循驼峰拼写法。 2、Color Highlight:高亮显示颜色值 3、Svg Preview: 实时预览svg图片(修改width、height、fill等值来实时查看效果) 4、…...

一文弄懂BFS【广度优先搜索(Breadth-First Search)】

BFS,全名为广度优先搜索(Breadth-First Search),是一种用于图或树的遍历或搜索的算法。它的主要思想是由节点自身开始向它的邻居节点新进展开搜索,因此也常被形象地称为“层序遍历”。 BFS 基本思想 BFS 工作原理是,从开始节点开…...

深度学习记录--logistic回归函数的计算图

计算图用于logistic回归函数 先回顾一下单一样本的logistic回归损失函数的公式,公式如下: 将logistic函数用计算图表示出来(以两个基础量为例),计算图如下: 前向传播已经完成,接下来完成后向传播 运用链式法则依次求…...

Java基本数据类型详解

✨个人主页:全栈程序猿的CSDN博客 💨系列专栏:Java从入门到精通 ✌座右铭:编码如诗,Bug似流星,持续追求优雅的代码,解决问题如同星辰般自如 Java是一种强类型语言,数据类型在程序中起…...

第十五届蓝桥杯模拟赛(第二期)

大家好,我是晴天学长,本次分享,制作不易,本次题解只用于学习用途,如果有考试需要的小伙伴请考完试再来看题解进行学习,需要的小伙伴可以点赞关注评论一波哦!后续会继续更新第三期的。&#x1f4…...

变量 varablie 声明- Rust 变量 let mut 声明与 C/C++ 变量声明对比分析

一、变量声明设计:let 与 mut 的哲学解析 Rust 采用 let 声明变量并通过 mut 显式标记可变性,这种设计体现了语言的核心哲学。以下是深度解析: 1.1 设计理念剖析 安全优先原则:默认不可变强制开发者明确声明意图 let x 5; …...

XCTF-web-easyupload

试了试php,php7,pht,phtml等,都没有用 尝试.user.ini 抓包修改将.user.ini修改为jpg图片 在上传一个123.jpg 用蚁剑连接,得到flag...

大模型多显卡多服务器并行计算方法与实践指南

一、分布式训练概述 大规模语言模型的训练通常需要分布式计算技术,以解决单机资源不足的问题。分布式训练主要分为两种模式: 数据并行:将数据分片到不同设备,每个设备拥有完整的模型副本 模型并行:将模型分割到不同设备,每个设备处理部分模型计算 现代大模型训练通常结合…...

MySQL用户和授权

开放MySQL白名单 可以通过iptables-save命令确认对应客户端ip是否可以访问MySQL服务: test: # iptables-save | grep 3306 -A mp_srv_whitelist -s 172.16.14.102/32 -p tcp -m tcp --dport 3306 -j ACCEPT -A mp_srv_whitelist -s 172.16.4.16/32 -p tcp -m tcp -…...

项目部署到Linux上时遇到的错误(Redis,MySQL,无法正确连接,地址占用问题)

Redis无法正确连接 在运行jar包时出现了这样的错误 查询得知问题核心在于Redis连接失败,具体原因是客户端发送了密码认证请求,但Redis服务器未设置密码 1.为Redis设置密码(匹配客户端配置) 步骤: 1).修…...

深度学习习题2

1.如果增加神经网络的宽度,精确度会增加到一个特定阈值后,便开始降低。造成这一现象的可能原因是什么? A、即使增加卷积核的数量,只有少部分的核会被用作预测 B、当卷积核数量增加时,神经网络的预测能力会降低 C、当卷…...

Selenium常用函数介绍

目录 一,元素定位 1.1 cssSeector 1.2 xpath 二,操作测试对象 三,窗口 3.1 案例 3.2 窗口切换 3.3 窗口大小 3.4 屏幕截图 3.5 关闭窗口 四,弹窗 五,等待 六,导航 七,文件上传 …...

怎么让Comfyui导出的图像不包含工作流信息,

为了数据安全,让Comfyui导出的图像不包含工作流信息,导出的图像就不会拖到comfyui中加载出来工作流。 ComfyUI的目录下node.py 直接移除 pnginfo(推荐)​​ 在 save_images 方法中,​​删除或注释掉所有与 metadata …...

安卓基础(Java 和 Gradle 版本)

1. 设置项目的 JDK 版本 方法1:通过 Project Structure File → Project Structure... (或按 CtrlAltShiftS) 左侧选择 SDK Location 在 Gradle Settings 部分,设置 Gradle JDK 方法2:通过 Settings File → Settings... (或 CtrlAltS)…...

FFmpeg avformat_open_input函数分析

函数内部的总体流程如下: avformat_open_input 精简后的代码如下: int avformat_open_input(AVFormatContext **ps, const char *filename,ff_const59 AVInputFormat *fmt, AVDictionary **options) {AVFormatContext *s *ps;int i, ret 0;AVDictio…...