cms垃圾收集器是如何进行垃圾回收的

2023-11-07

CMS 垃圾回收器

CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器。目前很大一部分的 Java 应用集中在互联网网站或者 B/S 系统的服务端上,这类应用尤其重视服务的响应速度,希望系统停顿时间最短,以给用户带来较好的体验。CMS 收集器就非常符合这类应用的需求。从名字(包含"Mark Sweep")上就可以看出,CMS 收集器是基于"标记-清除"算法实现的。

CMS 垃圾收集器属于老年代的收集器,以对应的新生代收集器为parNew。

核心垃圾回收过程

整个过程分为4个步骤,包括:

  1. 初始标记(CMS initial mark):初始标记仅仅只是标记一下GC Roots能直接关联到的对象,速度很快;
  2. 并发标记(CMS concurrent mark):该阶段就是进行 GC Roots Tracing 的过程;
  3. 重新标记(CMS remark):为了修正并发标记期间因用户程序继续运作而导致标记产生变动的那一部分对象的标记记录,这个阶段的停顿时间一般会比初始标记阶段稍长一些,但远比并发标记的时间短;
  4. 并发清除(CMS concurrent sweep)

其中,初始标记、重新标记这两个步骤仍然需要 “Stop The World”。由于整个过程中耗时最长的并发标记和并发清除过程收集器收集线程都可以与用户线程一起工作,所以,从总体上来说,CMS 收集器的内存回收过程是与用户线程一起并发执行的。
在这里插入图片描述

完整垃圾回收过程

CMS 完整处理过程有七个步骤:

  1. 初始标记(CMS-initial-mark) ,会导致swt(stop the world);
  2. 并发标记(CMS-concurrent-mark),与用户线程同时运行;
  3. 预清理(CMS-concurrent-preclean),与用户线程同时运行;
  4. 可被终止的预清理(CMS-concurrent-abortable-preclean) 与用户线程同时运行;
  5. 重新标记(CMS-remark) ,会导致swt;
  6. 并发清除(CMS-concurrent-sweep),与用户线程同时运行;
  7. 并发重置状态等待下次CMS的触发(CMS-concurrent-reset),与用户线程同时运行;

阶段一:初始标记

这是CMS中两次stop-the-world事件中的一次。这一步的作用是标记存活的对象,有两部分:

  • 标记老年代中所有的GC Roots对象(即直接被 GC Root 引用的对象),如下图节点1;

  • 标记年轻代中活着的对象引用到的老年代的对象(指的是年轻带中还存活的引用类型对象,引用指向老年代中的对象)如下图节点2、3;

在这里插入图片描述
在Java语言里,可作为GC Roots对象的包括如下几种:

  • 虚拟机栈(栈桢中的本地变量表)中的引用的对象 ;
  • 方法区中的类静态属性引用的对象 ;
  • 方法区中的常量引用的对象 ;
  • 本地方法栈中JNI的引用的对象;
  • Java虚拟机内部的引用,如基本数据类型对应的Class对象、一些常驻的异常对象(比如NullPointException,OutOfMemoryException)等,还有系统类加载器
  • 所有被同步锁(synchronized关键字)持有的对象
  • 反映java虚拟机内部情况的JMXBean、JVMTI中注册的回调、本地代码缓存等

ps:为了加快此阶段处理速度,减少停顿时间,可以开启初始标记并行化,-XX:+CMSParallelInitialMarkEnabled,同时调大并行标记的线程数,线程数不要超过cpu的核数;

阶段二:并发标记(Concurrent Mark)

在这个阶段垃圾收集器会遍历老年代,然后标记所有存活的对象,它会根据上个阶段找到的 GC Roots 遍历查找。

并发标记阶段,它会与用户的应用程序并发运行。并不是老年代的所有存活的对象都会被标记,因为在标记期间用户的程序可能会改变一些引用。(例如节点 3 下面节点的引用发生了改变)

从“初始标记”阶段标记的对象开始找出所有存活的对象;

因为是并发运行的,在运行期间会发生新生代的对象晋升到老年代、或者是直接在老年代分配对象、或者更新老年代对象的引用关系等等,对于这些对象,都是需要进行重新标记的,否则有些对象就会被遗漏,发生漏标的情况。

关于JVM卡标记(Card Marking),卡表(Card Table),写屏障(Write Barrier),参考:JVM之卡表(Card Table)

为了提高重新标记的效率,该阶段会把上述对象所在的Card标识为Dirty,后续只需扫描这些Dirty Card的对象,避免扫描整个老年代;
并发标记阶段只负责将引用发生改变的Card标记为Dirty状态,不负责处理;

如下图所示,也就是节点1、2、3,最终找到了节点4和5。并发标记的特点是和应用程序线程同时运行。并不是老年代的所有存活对象都会被标记,因为标记的同时应用程序会改变一些对象的引用等。
在这里插入图片描述

阶段三:并发预清理阶段

这也是一个并发阶段,与应用的线程并发运行,并不会 Stop 应用的线程,在并发运行的过程中,一些对象的引用可能会发生改变,但是这种情况发生时, JVM 会将包含这个对象的区域(Card)标记为 Dirty,这就是 Card marking。

在 Pre-clean 阶段,那些能够从 Dirty 对象到达的对象也会被标记,这个标记做完之后, Dirty Card 标记就会被清除了。

前一个阶段已经说明,不能标记出老年代全部的存活对象,是因为标记的同时应用程序会改变一些对象引用,这个阶段就是用来处理前一个阶段因为引用关系改变导致没有标记到的存活对象的,它会扫描所有标记为Dirty的Card。如下图所示,在并发清理阶段,节点3的引用指向了6;则会把节点3的card标记为Dirty;
在这里插入图片描述
最后将6标记为存活,如下图所示:

在这里插入图片描述

阶段四:可终止的预处理

这个阶段尝试着去承担下一个阶段Final Remark阶段足够多的工作。这个阶段持续的时间依赖好多的因素,由于这个阶段是重复的做相同的事情直到发生abort的条件(比如:重复的次数、多少量的工作、持续的时间等等)之一才会停止。
ps:此阶段最大持续时间为5秒,之所以可以持续5秒,另外一个原因也是为了期待这5秒内能够发生一次ygc,清理年轻代的引用,使得下个阶段的重新标记阶段,扫描年轻代指向老年代的引用的时间减少;

阶段五:重新标记

这个阶段会导致第二次stop the word,该阶段的任务是完成标记整个年老代的所有的存活对象
这个阶段,重新标记的内存范围是整个堆,包含_young_gen和_old_gen。

为什么要扫描新生代呢,因为对于老年代中的对象,如果被新生代中的对象引用,那么就会被视为存活对象,即使新生代的对象已经不可达了,也会使用这些不可达的对象当做cms的“gc root”,来扫描老年代; 因此对于老年代来说,引用了老年代中对象的新生代的对象,也会被老年代视作“GC ROOTS”。

当此阶段耗时较长的时候,可以加入参数-XX:+CMSScavengeBeforeRemark,在重新标记之前,先执行一次ygc,回收掉年轻带的对象无用的对象,并将对象放入幸存代或晋升到老年代,这样再进行年轻代扫描时,只需要扫描幸存代的对象即可,一般幸存代非常小,这大大减少了扫描时间。

由于之前的预处理阶段是与用户线程并发执行的,这时候可能年轻代的对象对老年代的引用已经发生了很多改变,这个时候,remark阶段要花很多时间处理这些改变,会导致很长stop the word,所以通常CMS尽量运行Final Remark阶段在年轻代是足够干净的时候,是为了减少连续 STW 发生的可能性(年轻代存活对象过多的话,也会导致老年代涉及的存活对象会很多)。

另外,还可以开启并行收集:-XX:+CMSParallelRemarkEnabled

至此,老年代所有存活的对象都被标记过了,现在可以通过清除算法去清理老年代不再使用的对象

阶段六:并发清理

通过以上5个阶段的标记,老年代所有存活的对象已经被标记并且现在要通过Garbage Collector采用清扫的方式回收那些不能用的对象了。
这个阶段主要是清除那些没有标记的对象并且回收空间;

由于CMS并发清理阶段用户线程还在运行着,伴随程序运行自然就还会有新的垃圾不断产生,这一部分垃圾出现在标记过程之后,CMS无法在当次收集中处理掉它们,只好留待下一次GC时再清理掉。这一部分垃圾就称为“浮动垃圾”。

在这里插入图片描述

阶段七:并发重置

这个阶段并发执行,重新设置CMS算法内部的数据结构,准备下一个CMS生命周期的使用。

CMS 优缺点总结

优点:并发收集、低停顿

通过将大量工作分散到并发处理阶段来减少 STW 时间

CMS收集器有3个明显的缺点:

缺点1:总吞吐量降低

CMS收集器对CPU资源非常敏感。在并发阶段,它虽然不会导致用户线程停顿,但是会因为占用了一部分线程而导致应用程序变慢,总吞吐量会降低。

默认启动的回收线程数为:(CPU 数量 + 3)/ 4,CPU 数量=4,回收线程占用 25 %左右的 CPU 资源,CPU 数量越多占用率越低。数量很小使用可以采用增量式并发收集器 i-CMS(Incremental Concurrent Mark Sweep),即在并发标记和清理的时候让 GC 线程和用户线程交替运行,减少独占,但是收集时间变长了,不建议使用。

缺点2:无法处理浮动垃圾

CMS收集器无法处理浮动垃圾,可能出现"Concurrent Mode Failure"失败而导致另一次Full GC的产生。由于CMS并发清理阶段用户线程还在运行着,伴随程序运行自然就还会有新的垃圾不断产生,这一部分垃圾出现在标记过程之后,CMS无法在当次收集中处理掉它们,只好留待下一次GC时再清理掉。这一部分垃圾就称为"浮动垃圾"。

因为垃圾收集阶段用户线程也在运行,就会不断产生垃圾,所以得预留一部分空间给用户线程使用,则不能等到老年代几乎全部被填满之后才进行垃圾回收, 1.6 之后当老年代使用 92%,CMS 就启动了,该值可以通过参数:-XX:CMSInitiatingOccupancyFraction 指定,该百分值太小则 GC 过于频繁,太大会导致预留内存无法满足程序需要,出现 “Concurrent Mode Failure”,这时候只能采用 Serial Old 收集器来进行老年代垃圾收集,更加浪费时间。

缺点3:空间碎片问题

CMS是一款基于标记-清除算法实现的收集器,所以会有空间碎片的现象,当空间碎片过多时,将会给大对象分配带来很大麻烦,往往会出现老年代还有很大空间剩余,但是无法找到足够大的连续空间来分配当前对象,不得不提前触发一次Full GC。

解决方案:通过参数:-XX:+UseCMSCompactAtFullCollection 开关参数(默认开启),用于在 CMS 收集器顶不住要进行 Full GC 时候开启内存碎片合并整理过程,该过程无法并发,停顿时间较长。

补充参数:-XX+CMSFullGCsBeforeCompaction 用于设置执行多少次不压缩的 Full GC 之后,跟着来一次带压缩的。默认值为 0 ,表示每次进入 Full GC 都进行碎片整理。

缺点4:GC 的时间难以预估

由于缺点2和缺点3的存在,对于堆比较大的应用, GC 的时间难以预估

代码验证及CMS GC日志解析

设置虚拟机参数为:-verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8 -XX:+UseConcMarkSweepGC 因为 CMS 只能运行到老年代,对应的新生代会自动采用与 CMS 对应的垃圾回收器

新生代为9216K

eden区为8/10,为8192K,

survivor from,to各自为1/10,为1024K

老年代为10240K,堆大小一共是10240+10240K = 20M

程序为:

package com.gjxaiou.gc;

/**
 * @Author GJXAIOU
 * @Date 2019/12/18 13:19
 */
public class MyTest5 {
    public static void main(String[] args) {
        int size = 1024 * 1024;
        byte[] myAlloc1 = new byte[4 * size];
        System.out.println("----111111111----");
        byte[] myAlloc2 = new byte[4 * size];
        System.out.println("----222222222----");
        byte[] myAlloc3 = new byte[4 * size];
        System.out.println("----333333333----");
        byte[] myAlloc4 = new byte[2 * size];
        System.out.println("----444444444----");
    }
}

输出结果:

// 前面没有执行任何的垃圾回收,因为 Eden 区域放置 4M 对象可以放下
----111111111----
// 因为第二次 new 又需要分配 4M 空间,Eden 空间不够用,使用垃圾回收,对应新生代是 ParNew 收集器
[GC (Allocation Failure) [ParNew: 5899K->670K(9216K), 0.0016290 secs] 5899K->4768K(19456K), 0.0016630 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
----222222222----

// 新生代垃圾回收
[GC (Allocation Failure) [ParNew: 5007K->342K(9216K), 0.0023932 secs] 9105K->9168K(19456K), 0.0024093 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 

// 老年代垃圾回收    
// cms-initial-mark 
// 8825K(10240K)  --  老年代存活对象占用空间大小(老年代总的空间大小)
// 13319K(19456K) --  整个堆存活对象占用空间大小(堆的空间大小)
[GC (CMS Initial Mark) [1 CMS-initial-mark: 8825K(10240K)] 13319K(19456K), 0.0003398 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[CMS-concurrent-mark-start]
----333333333----
----444444444----

Heap
 par new generation   total 9216K, used 6780K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000)
  eden space 8192K,  78% used [0x00000000fec00000, 0x00000000ff2499d0, 0x00000000ff400000)
  from space 1024K,  33% used [0x00000000ff400000, 0x00000000ff455a08, 0x00000000ff500000)
  to   space 1024K,   0% used [0x00000000ff500000, 0x00000000ff500000, 0x00000000ff600000)
 concurrent mark-sweep generation total 10240K, used 8825K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)
 Metaspace       used 3144K, capacity 4496K, committed 4864K, reserved 1056768K
  class space    used 343K, capacity 388K, committed 512K, reserved 1048576K

Process finished with exit code 0

另一段代码,将上面代码中的 byte[] myAlloc4 = new byte[2 * size]; 修改为:byte[] myAlloc4 = new byte[3 * size];得到的结果如下:

----111111111----
[GC (Allocation Failure) [ParNew: 5765K->637K(9216K), 0.0024098 secs] 5765K->4735K(19456K), 0.0024726 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
----222222222----
[GC (Allocation Failure) [ParNew: 4974K->240K(9216K), 0.0041475 secs] 9072K->9060K(19456K), 0.0041812 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
----333333333----
----444444444----
[GC (CMS Initial Mark) [1 CMS-initial-mark: 8819K(10240K)] 16522K(19456K), 0.0002890 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[CMS-concurrent-mark-start]

Heap
 par new generation   total 9216K, used 7764K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000)
  eden space 8192K,  91% used[CMS-concurrent-mark: 0.001/0.001 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
// 并发预清理 preclean
[CMS-concurrent-preclean-start]
[CMS-concurrent-preclean: 0.000/0.000 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
// 可终止的预处理 abortable-preclean
[CMS-concurrent-abortable-preclean-start]
[CMS-concurrent-abortable-preclean: 0.000/0.000 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
 [0x00000000fec00000, 0x00000000ff358e70, 0x00000000ff400000)
  from space 1024K,  23% used [0x00000000ff400000, 0x00000000ff43c2d0, 0x00000000ff500000)
  to   space 1024K,   0% used [0x00000000ff500000, 0x00000000ff500000, 0x00000000ff600000)
 concurrent mark-sweep generation total 10240K, used 8819K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)
 Metaspace       used 3126K, capacity 4496K, committed 4864K, reserved 1056768K
  class space    used 338K, capacity 388K, committed 512K, reserved 1048576K

Process finished with exit code 0

CMS应用

在中间件中,当需要尽量小的gc停顿时间时,会使用CMS

  • 查看logstash和elasticsearch进程,其young generation使用ParNew,old generation使用CMS
  • rocketmq,其NameSrv使用的是ParNew,CMS
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

cms垃圾收集器是如何进行垃圾回收的 的相关文章

  • Java中静态字段的确切含义是什么?

    我想在同一类对象的各个实例之间共享一个对象 从概念上讲 当我的程序运行时 A 类的所有对象都访问 B 类的同一个对象 我见过那个static是系统范围的 并且不鼓励使用它 这是否意味着如果我有另一个程序在实例化 A 类对象的同一个 JVM
  • 以编程方式设置最大 Java 堆大小

    有没有办法以编程方式设置最大 java 堆大小而不是作为 vm 参数 就像是 System getProperties put
  • getResourceAsStream(file) 在哪里搜索文件?

    我很困惑getResourceAsStream 我的包结构如下 src net floodlightcontroller invoked getResourceAsStream here resources floodlightdefaul
  • Scala 泛型 - 为什么我无法在泛型类中创建参数化对象?

    我目前正在学习scala 为什么此代码不起作用 class GenClass T var d T var elems List T Nil def dosom x T var y new T y 我得到 错误 需要类类型 但找到了 T 代替
  • Java 堆被无法访问的对象淹没

    我们的 Java EE 应用程序开始出现一些严重问题 具体来说 应用程序在启动后几分钟内就运行了高达 99 的老年代堆 不会抛出 OOM 但实际上 JVM 没有响应 jstat 显示老年代的大小根本没有减少 没有垃圾收集正在进行 并且kil
  • 如何在JVM不退出的情况下多次运行Java程序?

    假设我有一个Java程序Test class 如果我使用下面的脚本 for i in 1 10 do java Test done JVM每次都会退出java Test被调用 我想要的是跑步java Test在不退出JVM的情况下多次执行
  • 为什么 JVM 同时具有“invokespecial”和“invokestatic”操作码?

    两条指令都使用静态而不是动态调度 似乎唯一的实质性区别是invokespecial始终将一个对象作为其第一个参数 该对象是分派方法所属类的实例 然而 invokespecial实际上并没有把物体放在那里 编译器负责通过在发出之前发出适当的堆
  • 最近有关于 JVM 的书吗? [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • 如何计算Java数组的内存大小?

    我知道如何通过添加三个部分来计算Java对象的内存大小 标头 属性 引用 我还知道Java数组也是一个对象 但是当我读到 Understanding the JVM Advanced Features and Best Practices
  • 什么触发了java垃圾收集器

    我对 Java 中垃圾收集的工作原理有点困惑 我知道当不再有对某个对象的实时引用时 该对象就有资格进行垃圾回收 但是如果它有对实时对象的引用怎么办 可以说我有一个节点集合 它们再次引用更多节点 List 1 gt Node a gt Nod
  • Java 接口合成方法生成,同时缩小返回类型

    我有 2 个接口和 2 个返回类型 interface interfaceA Publisher
  • JVM 是否会内联对象的实例变量和方法?

    假设我有一个非常紧密的内部循环 每次迭代都会访问和改变一个簿记对象 该对象存储有关算法的一些简单数据 并具有用于操作它的简单逻辑 簿记对象是私有的和最终的 并且它的所有方法都是私有的 最终的和 inline 下面是一个示例 Scala 语法
  • 为什么不在下一个 JVM 中删除类型擦除呢?

    Java 在 Java 5 中引入了泛型类型擦除 因此它们可以在旧版本的 Java 上运行 这是兼容性的权衡 我们已经失去了这种兼容性 1 https stackoverflow com questions 22610400 a progr
  • 当目标是属性时,@Throws 不起作用

    在看的同时这个问题 https stackoverflow com q 47737288 7366707 我注意到申请 Throws to a get or setuse site 没有影响 此外 唯一有效的目标 for Throws ar
  • Java 类:匿名类、嵌套类、私有类

    有人能解释一下Java中匿名类 嵌套类和私有类之间的区别吗 我想知道与每个相关的运行时成本以及每个编译器的方法 这样我就可以掌握哪个最适合用于例如性能 编译器优化的潜力 内存使用以及其他 Java 编码人员的普遍可接受性 我所说的匿名类是指
  • 在进行堆转储后,如何在发生 OutOfMemoryError 时重新启动 JVM?

    我知道关于 XX HeapDumpOnOutOfMemoryError https stackoverflow com q 542979 260805JVM 参数 我也知道 XX OnOutOfMemoryError cmd args cm
  • Java 中清除嵌套 Map 的好方法

    public class MyCache AbstractMap
  • 抛出 Java 异常时是否会生成堆栈跟踪?

    这是假设我们不调用 printstacktrace 方法 只是抛出和捕获 我们正在考虑这样做是为了解决一些性能瓶颈 不 堆栈跟踪是在构造异常对象时生成的 而不是在抛出异常对象时生成的 Throwable 构造函数调用 fillInStack
  • 通过SOCKS代理连接Kafka

    我有一个在 AWS 上运行的 Kafka 集群 我想用标准连接到集群卡夫卡控制台消费者从我的应用程序服务器 应用程序服务器可以通过 SOCKS 代理访问互联网 无需身份验证 如何告诉 Kafka 客户端通过代理进行连接 我尝试了很多事情 包
  • jvm 次要版本与编译器次要版本

    当运行使用具有相同主要版本但次要版本高于 JVM 的 JDK 编译的类时 JVM 会抛出异常吗 JDK 版本并不重要 类文件格式版本 http blogs oracle com darcy entry source target class

随机推荐

  • Unity打包的apk在安卓4.4.2盒子上碰到的问题

    项目场景 Unity开发的项目需要在安卓4 4 2盒子上运行 问题描述 1 会出 从顶部向下滑动即可退出全屏模式 的弹框 这是android4 4的一个特性 叫做沉浸模式 Full screen Immersive Mode 当app启用该
  • 要庆幸,找到了自己-------Day73

    跟朋友聊了大半晚上 看看时间 已经要睡觉的点了 坐下来写这篇文章 只为了感念下曾经的自己 如今的自己 未来的自己 就那么迷茫了那么多年 也坚守了那么多年 如果有方法可以做到 那为何不去努力呢 如果没有人帮 那就自己去克服它 那个守望的孩子就
  • 使用Nginx+Keepalived组建高可用负载平衡Web server集群

    一 首先说明一下网络拓扑结构 1 Nginx 反向代理Server HA Nginx master 192 168 1 157 Nginx backup 192 168 1 158 虚拟IP统一为 192 168 1 110 2 web服务
  • 信号和槽的绑定

    为了更加深入的理解信号和槽的绑定 我们使用以下2种方法来实现绑定 比如我们在QT degisnger界面中添加一个label控件和horizontalScrollBar控件 我们想实现 拖动horizontalScrollBar进度条 la
  • 使用STM32组建基于LoRa的环境监测系统

    文章目录 一 前言 二 介绍 三 硬件连接 1 系统框架 2 中心网关的连接 3 传感器节点1的连接 4 传感器节点2的连接 四 网关程序 1 主程序设计 2 LoRa程序 3 串口1程序 4 LCD显示程序 五 传感器节点程序 1 传感器
  • hexo+git搭建个人博客

    前言 喜欢写 Blog 的人 会经历三个阶段 第一阶段 刚接触 Blog 觉得很新鲜 试着选择一个免费空间来写 第二阶段 发现免费空间限制太多 就自己购买域名和空间 搭建独立博客 第三阶段 觉得独立博客的管理太麻烦 最好在保留控制权的前提下
  • JUC三连问

    1 进程和线程的区别 1 进程是资源分配的基本单位 线程是程序执行的最小单位 2 一个进程包括多个线程 3 每个进程都有自己的内存和资源 一个进程中的线程会共享这些内存和资源 每个线程都有单独的栈内存 和寄存器 2 并行和并发的区别 并行指
  • java 数据结构----------堆栈和队列

    队列的基本概念 队列 简称队 也是一种特殊的线性表 队列的数据元素以及数据元素间的逻辑关系和线性表完全相同 差别是线性表允许在任意位置插入和删除 而队列只允许在一端进行插入操作而在另一端进行删除操作 队列中允许插入操作的一端称为队尾 允许进
  • AutoConfigurationImportSelector自动导入过程分析

    AutoConfigurationImportSelector AutoConfigurationImportSelector 类实现 DeferredImportSelector接口 在项目启动过程中 会自动调用其 selectImpor
  • html input框的样式修改

    在html中 往往我们需要修改input中的placeholder默认文字的样式 在这个时候主要用到 在input框中有时想将输入的字和placeholder设为不同的颜色或其它效果 这时就可以用以下代码来对placeholder进行样式设
  • 基数排序C/C++代码实现

    链式基数排序 分配类排序不需要比较关键字的大小 它 是根据关键字中各位的值 通过对待排序记录进行若干趟 分配 与 收集 来实现排序的 是一种 借助于多关键字排序的思想对单关键字排序的方法 基数排序 RadixSorting 是典型的分配类排
  • Tomcat配置与优化(内存、并发、管理)

    一 JVM内存配置优化 在开发当中 当一个项目比较大时 依赖的jar包通常比较多 我们都知道 在应用服务器启动时 会将应用引用到的所有类通过ClassLoader依次全部加载到内存当中 Java的逻辑内存模型大致分为堆内存 栈内存 静态内存
  • 10.机器学习sklearn-------手写数字识别实例

    1 概念介绍 图像识别 Image Recognition 是指利用计算机对图像进行处理 分析和理解 以识别各种不同模式的目标和对像的技术 图像识别的发展经历了三个阶段 文字识别 数字图像处理与识别 物体识别 机器学习领域一般将此类识别问题
  • java作业-----方法重载

    满足方法重载的条件 1 方法名相同 2 参数类型不同 参数个数不同 参数类型的顺序不同 同时 方法的返回值不作为方法重载的判断条件 转载于 https www cnblogs com xinshngqi p 11599814 html
  • cmd 复制文件夹,包括文件夹本身,xcopy复制 指定目录,选定目录复制

    cmd 复制文件夹 包括文件夹本身 或者包括目录本身 或者xcopy复制 指定目录 我们发现 xcopy好像没这个功能 但是可以间接实现选定的目录拷贝 举例 我有个目录 a c a 要复制到 d盘 先第一步 cd d mkdir a xco
  • 整数对最小和

    题目 整数对最小和 输入描述 输入两行整形数组array1 array2 每行首个数字为数组大小size 0
  • C++浅拷贝和深拷贝——使用(代码演示篇)

    浅拷贝 普通类型的成员变量 深拷贝 成员变量是不是有指针类型 数组类型或者其他类的引用的时候 深拷贝 代码演示 define CRT SECURE NO WARNINGS include
  • 使用Python开发一个恐龙跑跑小游戏,玩起来

    相信很多人都玩过 chrome 浏览器上提供的恐龙跑跑游戏 在我们断网或者直接在浏览器输入地址 chrome dino 都可以进入游戏 今天我们就是用 Python 来制作一个类似的小游戏 素材准备 首先我们准备下游戏所需的素材 比如恐龙图
  • k8s flannel vxlan流量抓包分析

    Flannel Vxlan抓包 对于 Kubernetes 集群中的 Pod 由于容器内不便于抓包 通常视情况在 Pod 数据包经过的 veth 设备 docker0 网桥 CNI 插件设备 如 cni0 flannel 1 etc 及 P
  • cms垃圾收集器是如何进行垃圾回收的

    文章目录 CMS 垃圾回收器 核心垃圾回收过程 完整垃圾回收过程 阶段一 初始标记 阶段二 并发标记 Concurrent Mark 阶段三 并发预清理阶段 阶段四 可终止的预处理 阶段五 重新标记 阶段六 并发清理 阶段七 并发重置 CM