文章目录

  • 1.年轻代收集器
    • 1.1 Serial收集器
    • 1.2 ParNew收集器
    • 1.3 Parallel Scavenge收集器
  • 2.老年代收集器
    • 2.1 Serial Old收集器
    • 2.2 Parallel Old收集器
    • 2.3 CMS收集器
  • 3.G1收集器
  • 4.三色标记法与现代垃圾回收器
  • 5.几种垃圾收集器对比及使用场景

1.年轻代收集器

  年轻代收集器包括Serial收集器、ParNew收集器以及Parallel Scavenge收集器。

1.1 Serial收集器

  Serial收集器是一款年轻代的垃圾收集器,使用复制算法。它是一款发展历史最悠久的垃圾收集器。Serial收集器只能使用一条线程进行垃圾收集工作,在串行处理器中minor和major GC过程都是用一个线程进行回收的。它的最大特点是在进行垃圾回收时,需要对所有正在执行的线程暂停STW(stop the world —— 在进行垃圾收集的时候,所有的工作线程都需要停止工作,等待垃圾收集线程完成以后,其他线程才可以继续工作),几十毫秒的停顿对于大多数应用还是可以接受的,该收集器适用于单CPU、新生代空间较小且对暂停时间要求不是特别高的应用上,是client级别的默认GC方式。工作过程可以简单的用下图来表示:

  从图中可以看到,Serial收集器工作的时候,其他用户线程都停止下来,等到GC过程结束以后,它们才继续执行。而且处理GC过程的只有一条线程在执行。由于Serial收集器的这种工作机制,所以在进行垃圾收集过程中,会出现STW(Stop The World)的情况,应用程序会出现停顿的状况。如果垃圾收集的时间很长,那么停顿时间也会很长,这样会导致系统响应变的迟钝,影响系统的时候。

  虽然这款年迈的垃圾收集器只能使用单核CPU,但是正是由于它不能利用多核,在一些场景下,减少了很多线程的上下文切换的开销,可以在进行垃圾收集过程中专心处理GC过程,而不会被打断,所以如果GC过程很短暂,那么这款收集器还是非常简单高效的。

  由于Serial收集器只能使用单核CPU,在现代处理器基本都是多核多线程的情况下,为了充分利用多核的优势,出现了多线程版本的垃圾收集器,比如下面将要说到的ParNew收集器。

1.2 ParNew收集器

  ParNew垃圾收集器是Serial收集器的多线程版本,提高了效率,这样它就可以被用于服务端上(server),同时它可以与CMS GC配合,所以,更加有理由将他用于server端。其使用复制算法。为了利用CPU多核多线程的优势,ParNew收集器可以运行多个收集线程来进行垃圾收集工作。这样可以提高垃圾收集过程的效率。

  和上面的Serial收集器比较,可以明显看到,在垃圾收集过程中,GC线程是多线程执行的,而在Serial收集器中,只有一个GC线程在处理垃圾收集过程。ParNew收集器在很多时候都是作为服务端的年轻代收集器的选择,除了它具有比Serial收集器更好的性能外,还有一个原因是,多线程版本的年轻代收集器中,只有它可以和CMS这款优秀的老年代收集器一起搭配搭配使用。

  作为一款多线程收集器,当它运行在单CPU的机器上的时候,由于不能利用多核的优势,在线程收集过程中可能会出现频繁上下文切换,导致额外的开销,所以在单CPU的机器上,ParNew收集器的性能不一定好于Serial这款单线程收集器。如果机器是多CPU的,那么ParNew还是可以很好的提高GC收集的效率的。

  ParNew收集器默认开启的垃圾收集线程数是和当前机器的CPU数量相同的,为了控制GC收集线程的数量,可以通过参数-XX:ParallelGCThreads来控制垃圾收集线程的数量。

1.3 Parallel Scavenge收集器

  Parallel Scavenge收集器是是一款年轻代的收集器,它使用复制算法,在整个扫描和复制过程采用多线程的方式进行,适用于多CPU、对暂停时间要求较短的应用,是server级别的默认GC方式。和ParNew一样,它也会一款多线程的垃圾收集器,但是它又和ParNew有很大的不同点。

  Parallel Scavenge收集器和其他收集器的关注点不同。其他收集器,比如ParNew和CMS这些收集器,它们主要关注的是如何缩短垃圾收集的时间。而Parallel Scavenge收集器关注的是如何控制系统运行的吞吐量。这里说的吞吐量,指的是CPU用于运行应用程序的时间和CPU总时间的占比,吞吐量 = 代码运行时间 / (代码运行时间 + 垃圾收集时间)。如果虚拟机运行的总的CPU时间是100分钟,而用于执行垃圾收集的时间为1分钟,那么吞吐量就是99%。

  直观上,好像以缩短垃圾收集的停顿时间为目的和以控制吞吐量为目的差不多,但是适用的场景却不同。对于那些桌面应用程序,为了得到良好的用户体验,在交互过程中,需要得到快速的响应,所以系统的停顿时间要尽可能的快以避免影响到系统的响应速度,只要保证每次停顿的时间很短暂,假设每次停顿时间为10ms,那么即使发生很多次的垃圾收集过程,假设1000次,也不会影响到系统的响应速度,不会影响到用户的体验。对于一些后台计算任务,它不需要和用户进行交互,所以短暂的停顿时间对它而言并不需要,对于计算任务而言,更好的利用CPU时间,提高计算效率才是需要的,所以假设每次停顿时间相对很长,有100ms,而由于花费了很长的时间进行垃圾收集,那么垃圾收集的次数就会降下来,假设只有5次,那么显然,使用以吞吐量为目的的垃圾收集器,可以更加有效的利用CPU来完成计算任务。所以,在用户界面程序中,使用低延迟的垃圾收集器会有很好的效果,而对于后台计算任务的系统,高吞吐量的收集器才是首选。

  Parallel Scavenge收集器提供了两个参数用于控制吞吐量。-XX:MaxGCPauseMillis用于控制最大垃圾收集停顿时间,-XX:GCTimeRatio用于直接控制吞吐量的大小。MaxGCPauseMillis参数的值允许是一个大于0的整数,表示毫秒数,收集器会尽可能的保证每次垃圾收集耗费的时间不超过这个设定值。但是如果这个这个值设定的过小,那么Parallel Scavenge收集器为了保证每次垃圾收集的时间不超过这个限定值,会导致垃圾收集的次数增加和增加年轻代的空间大小,垃圾收集的吞吐量也会随之下降。GCTimeRatio这个参数的值应该是一个0-100之间的整数,表示应用程序运行时间和垃圾收集时间的比值。如果把值设置为19,即系统运行时间 : GC收集时间 = 19 : 1,那么GC收集时间就占用了总时间的5%(1 / (19 + 1) = 5%),该参数的默认值为99,即最大允许1%(1 / (1 + 99) = 1%)的垃圾收集时间。

  Parallel Scavenge收集器还有一个参数:-XX:UseAdaptiveSizePolicy。这是一个开关参数,当开启这个参数以后,就不需要手动指定新生代的内存大小(-Xmn)、Eden区和Survivor区的比值(-XX:SurvivorRatio)以及晋升到老年代的对象的大小(-XX:PretenureSizeThreshold)等参数了,虚拟机会根据当前系统的运行情况动态调整合适的设置值来达到合适的停顿时间和合适的吞吐量,这种方式称为GC自适应调节策略。

  Parallel Scavenge收集器也是一款多线程收集器,但是由于目的是为了控制系统的吞吐量,所以这款收集器也被称为吞吐量优先收集器。


2.老年代收集器

  老年代收集包括:Serial Old收集器、Parallel Old收集器以及CMS收集器。

2.1 Serial Old收集器

  Serial Old收集器是Serial收集器的老年代版本,它也是一款使用"标记-整理(标记-压缩)"算法的单线程的垃圾收集器,主要使用在Client模式下的虚拟机。这款收集器主要用于客户端应用程序中作为老年代的垃圾收集器,也可以作为服务端应用程序的垃圾收集器,当它用于服务端应用系统中的时候,主要是在 JDK 5 版本之前和Parallel Scavenge年轻代收集器配合使用,或者作为CMS收集器的后备收集器。

2.2 Parallel Old收集器

  Parallel Old收集器是Parallel Scavenge收集器的老年代版本,使用"标记-整理"算法。这个收集器是在 JDK 6 版本中出现的,所以在 JDK 6 之前,新生代的Parallel Scavenge只能和Serial Old这款单线程的老年代收集器配合使用。Parallel Old垃圾收集器和Parallel Scavenge收集器一样,也是一款关注吞吐量的垃圾收集器,和Parallel Scavenge收集器一起配合,可以实现对Java堆内存的吞吐量优先的垃圾收集策略。

  Parallel Old垃圾收集器的工作原理和Parallel Scavenge收集器类似。

2.3 CMS收集器

  CMS收集器是老年代收集器中比较优秀的垃圾收集器。CMS是Concurrent Mark Sweep,从名字可以看出,这是一款使用"标记-清除"算法的并发收集器。CMS
垃圾收集器的目标是解决Serial GC停顿的问题,以获取最短停顿(回收)时间。由于现代互联网中的应用,比较重视服务的响应速度和系统的停顿时间,因其高并发、高响应的特点故常应用于B/S架构。(对 JDK 9 及以上版本的HotSpot虚拟机使用参数-XX:+UseConcMarkSweepGC来开启CMS收集器的话,用户会收到一个警告信息,提示CMS未来将会被废弃;在 JDK 14 中使用-XX:+UseConcMarkSweepGC的话,JVM不会报错,只是给出一个warning信息,但是不会exit。JVM会自动回退以默认GC方式启动JVM。前辈珍重,走好不送。)

  CMS收集器的优点:并发收集、低停顿,但远没有达到完美;

  CMS收集器的缺点

    CMS收集器对CPU资源非常敏感,在并发阶段虽然不会导致用户停顿,但是会占用CPU资源而导致应用程序变慢,总吞吐量下降。
    CMS收集器无法处理浮动垃圾,可能出现“Concurrnet Mode Failure”,失败而导致另一次的Full GC。
    CMS收集器是基于标记-清除算法的实现,因此也会产生碎片。

  CMS收集器的运行过程相对上面提到的几款收集器要复杂一些,如下图示:

  从图中可以看出,CMS收集器的工作过程可以分为4个阶段:

     初始标记(CMS initial mark)阶段
     并发标记(CMS concurrent mark)阶段
     重新标记(CMS remark)阶段
     并发清除(CMS concurrent sweep)阶段

  从图中可以看出,在这4个阶段中,初始标记和重新标记这两个阶段都是只有GC线程在运行,用户线程会被停止,所以这两个阶段会发送STW(Stop The World)。初始标记阶段的工作是标记GC Roots可以直接关联到的对象,速度很快。并发标记阶段,会从GC Roots 出发,标记处所有可达的对象,这个过程可能会花费相对比较长的时间,但是由于在这个阶段,GC线程和用户线程是可以一起运行的,所以即使标记过程比较耗时,也不会影响到系统的运行。重新标记阶段,是对并发标记期间因用户程序运行而导致标记变动的那部分记录进行修正,重新标记阶段耗时一般比初始标记稍长,但是远小于并发标记阶段。最终,会进行并发清理阶段,和并发标记阶段类似,并发清理阶段不会停止系统的运行,所以即使相对耗时,也不会对系统运行产生大的影响。

  由于并发标记和并发清理阶段是和应用系统一起执行的,而初始标记和重新标记相对来说耗时很短,所以可以认为CMS收集器在运行过程中,是和应用程序是并发执行的。由于CMS收集器是一款并发收集和低停顿的垃圾收集器,所以CMS收集器也被称为并发低停顿收集器。

  虽然CMS收集器可以是实现低延迟并发收集,但是也存在一些不足。

  首先,CMS收集器对CPU资源非常敏感。对于并发实现的收集器而言,虽然可以利用多核优势提高垃圾收集的效率,但是由于收集器在运行过程中会占用一部分的线程,这些线程会占用CPU资源,所以会影响到应用系统的运行,会导致系统总的吞吐量降低。CMS默认开始的回收线程数是(Ncpu + 3) / 4,其中Ncpu是机器的CPU数。所以,当机器的CPU数量为4个以上的时候,垃圾回收线程将占用不少于%25的CPU资源,并且随着CPU数量的增加,垃圾回收线程占用的CPU资源会减少。但是,当CPU资源少于4个的时候,垃圾回收线程占用的CPU资源的比例会增大,会影响到系统的运行,假设有2个CPU的情况下,垃圾回收线程将会占据超过50%的CPU资源。所以,在选用CMS收集器的时候,需要考虑,当前的应用系统,是否对CPU资源敏感。

  其次,CMS收集器在处理垃圾收集的过程中,可能会产生浮动垃圾,由于它无法处理浮动垃圾,所以可能会出现Concurrent Mode Failure问题而导致触发一次Full GC。所谓的浮动垃圾,是由于CMS收集器的并发清理阶段,清理线程是和用户线程一起运行,如果在清理过程中,用户线程产生了垃圾对象,由于过了标记阶段,所以这些垃圾对象就成为了浮动垃圾,CMS无法在当前垃圾收集过程中集中处理这些垃圾对象。由于这个原因,CMS收集器不能像其他收集器那样等到完全填满了老年代以后才进行垃圾收集,需要预留一部分空间来保证当出现浮动垃圾的时候可以有空间存放这些垃圾对象。在 JDK 5 中,默认当老年代使用了68%的时候会激活垃圾收集,这是一个保守的设置,如果在应用中老年代增长不是很快,可以通过参数"-XX:CMSInitiatingOccupancyFraction"控制触发的百分比,以便降低内存回收次数来提供性能。在 JDK 6 中,CMS收集器的激活阀值变成了92%。如果在CMS运行期间没有足够的内存来存放浮动垃圾,那么就会导致"Concurrent Mode Failure"失败,这个时候,虚拟机将启动后备预案,临时启动Serial Old收集器来对老年代重新进行垃圾收集,这样会导致垃圾收集的时间边长,特别是当老年代内存很大的时候。所以对参数"-XX:CMSInitiatingOccupancyFraction"的设置,过高,会导致发生Concurrent Mode Failure,过低,则浪费内存空间。

  CMS的最后一个问题,就是它在进行垃圾收集时使用的"标记-清除"算法。上一篇文章介绍垃圾回收原理的时候,我们讲到"标记-清除"算法,在进行垃圾清理以后,会出现很多内存碎片,过多的内存碎片会影响大对象的分配,会导致即使老年代内存还有很多空闲,但是由于过多的内存碎片,不得不提前触发垃圾回收。为了解决这个问题,CMS收集器提供了一个"-XX:+UseCMSCompactAtFullCollection"参数,用于CMS收集器在必要的时候对内存碎片进行压缩整理。由于内存碎片整理过程不是并发的,所以会导致停顿时间变长。"-XX:+UseCMSCompactAtFullCollection"参数默认是开启的。虚拟机还提供了一个"-XX:CMSFullGCsBeforeCompaction"参数,来控制进行过多少次不压缩的Full GC以后,进行一次带压缩的Full GC,默认值是0,表示每次在进行Full GC前都进行碎片整理。

  虽然CMS收集器存在上面提到的这些问题,但是毫无疑问,CMS当前仍然是非常优秀的垃圾收集器。


  上面简单介绍了多款不同的垃圾收集器,虽然它们的特性不同,但是有些GC收集器可以组合使用来应对不同的应用的业务场景。下图给出了不同收集器以及它们之间是否兼容,互相兼容的收集器可以组合使用。


3.G1收集器

  G1 收集器是 JDK 7 才正式引用的商用收集器,现在已经成为 JDK 9 默认的收集器。前面几款收集器收集的范围都是新生代或者老年代,G1 进行垃圾收集的范围是整个堆内存,它采用 “ 化整为零 ” 的思路,把整个堆内存划分为多个大小相等的独立区域(Region),每个Region是逻辑连续的一段内存,在 G1 收集器中还保留着新生代和老年代的概念,它们分别都是一部分 Region,如下图:

  每个Region被标记了E、S、O和H,说明每个Region在运行时都充当了一种角色,其中H是以往算法中没有的,它代表Humongous,这表示这些Region存储的是巨型对象(humongous object,H-obj),如果一个对象占用的空间达到或者超过了分区容量50%以上,G1收集器就认为这是一个巨型对象。这些巨型对象,默认直接会被分配在老年代,但是如果它是一个短期存在的巨型对象,就会对垃圾收集器造成负面影响。为了解决这个问题,G1划分了一个Humongous区,它用来专门存放巨型对象。如果一个H区装不下一个巨型对象,那么G1会寻找连续的H分区来存储。为了能找到连续的H区,有时候不得不启动Full GC。

  每个区域可能是 Eden、Survivor、老年代,每种区域的数量也不一定。JVM 启动时会自动设置每个区域的大小(1M ~ 32M,必须是 2 的次幂),最多可以设置 2048 个区域(即支持的最大堆内存为 32M*2048 = 64G),假如设置 -Xmx8g -Xms8g,则每个区域大小为 8g/2048=4M。

  为了在 GC Roots Tracing 的时候避免扫描全堆,在每个 Region 中,都有一个 Remembered Set 来实时记录该区域内的引用类型数据与其他区域数据的引用关系(在前面的几款分代收集中,新生代、老年代中也有一个 Remembered Set 来实时记录与其他区域的引用关系),在标记时直接参考这些引用关系就可以知道这些对象是否应该被清除,而不用扫描全堆的数据。RSet记录了其他Region中的对象引用本Region中对象的关系,属于points-into结构(谁引用了我的对象)。RSet的价值在于使得垃圾收集器不需要扫描整个堆找到谁引用了当前分区中的对象,只需要扫描RSet即可。

  这里引入了卡表的技术,考虑如下场景,在Young GC的时候,老年代的对象可能引用新生代的对象,那么在标记年轻代存活对象的时候,就需要全堆扫描老年代中的所有对象才能确定那些该回收那些不该回收,成本极高。HotSpot给出的解决方案是一项叫做卡表(Card Table)的技术。该技术将整个堆划分为一个个大小介于128到512字节的卡,并且维护一个卡表,用来存储每张卡的一个标识位。这个标识位代表对应的卡是否可能存有指向新生代对象的引用。如果可能存在,那么我们就认为这张卡是脏的。在进行Minor GC的时候,我们便可以不用扫描整个老年代,而是在卡表中寻找脏卡,并将脏卡中的对象加入到Minor GC的GC Roots里。当完成所有脏卡的扫描之后,Java虚拟机便会将所有脏卡的标识位清零。想要保证每个可能有指向新生代对象引用的卡都被标记为脏卡,那么Java虚拟机需要截获每个引用型实例变量的写操作,并作出对应的写标识位操作。卡表能用于减少老年代的全堆空间扫描,这能很大的提升GC效率。

  卡表就是将一个Region区分为若干个card,组成的一张card表,可以将其理解为数组card[i],Rset的存储结构就相当于hashMap,key值为引用当前Region区的另外一个Region区的内存地址,value就是另外一个Region区中引用本Region区的card的索引值,意思就是GC可以通过Rset快速找到是哪个Region的哪个card对本Region进行了引用。

  G1 收集器可以 “ 建立可预测的停顿时间模型 ”,并基于目标来选择进行垃圾回收的区块数量。它维护了一个列表用于记录每个 Region 回收的价值大小(回收后获得的空间大小以及回收所需时间的经验值),这样可以保证 G1 收集器在有限的时间内可以获得最大的回收效率。G1 采用增量回收的方式,每次回收一些区块,而不是整堆回收。它会尽力满足我们的停顿时间要求,但也不是绝对的,它基于之前垃圾收集的数据统计,估计出在用户指定的停顿时间内能收集多少个区块。
  MixedGC的过程:如下图所示,G1 收集器收集器收集过程有初始标记、并发标记、最终标记、筛选回收,和 CMS 收集器前几步的收集过程很相似:如下图所示,G1 收集器收集器收集过程有初始标记、并发标记、最终标记、筛选回收,和 CMS 收集器前几步的收集过程很相似:

  ① 初始标记:标记出 GC Roots 直接关联的对象,这个阶段速度较快,需要停止用户线程,单线程执行。

  ② 并发标记:从 GC Root 开始对堆中的对象进行可达新分析,找出存活对象,这个阶段耗时较长,但可以和用户线程并发执行。

  ③ 最终标记:修正在并发标记阶段引用户程序执行而产生变动的标记记录。

  ④ 筛选回收:筛选回收阶段会对各个 Region 的回收价值和成本进行排序,根据用户所期望的 GC 停顿时间来指定回收计划(用最少的时间来回收包含垃圾最多的区域,这就是 Garbage First 的由来——第一时间清理垃圾最多的区块),这里为了提高回收效率,并没有采用和用户线程并发执行的方式,而是停顿用户线程。这些垃圾回收被称作“混合式”是因为他们不仅仅进行正常的新生代垃圾收集,同时也回收部分后台扫描线程标记的分区。

  垃圾回收的并发标记阶段,gc线程和应用线程是并发执行的,所以一个对象被标记之后,应用线程可能篡改对象的引用关系,从而造成对象的漏标、误标,其实误标没什么关系,顶多造成浮动垃圾,在下次gc还是可以回收的,但是漏标的后果是致命的,把本应该存活的对象给回收了,从而影响的程序的正确性。为了解决在并发标记过程中,存活对象漏标的情况,GC HandBook把对象分成三种颜色,也就是常提及到的三色标记法

  适用场景:要求尽可能可控 GC 停顿时间;内存占用较大的应用。可以用 -XX:+UseG1GC 使用 G1 收集器,JDK 9 默认使用 G1 收集器。


4.三色标记法与现代垃圾回收器

  现代追踪式(可达性分析)的垃圾回收器几乎都借鉴了三色标记的算法思想,尽管实现的方式不尽相同:比如白色/黑色集合一般都不会出现(但是有其他体现颜色的地方)、灰色集合可以通过栈/队列/缓存日志等方式进行实现、遍历方式可以是广度/深度遍历等等。

  对于读写屏障,以Java HotSpot VM为例,其并发标记时对漏标的处理方案如下:
    CMS:写屏障 + 增量更新
    G1:写屏障 + SATB
    ZGC:读屏障

  工程实现中,读写屏障还有其他功能,比如写屏障可以用于记录跨代/区引用的变化,读屏障可以用于支持移动对象的并发执行等。功能之外,还有性能的考虑,所以对于选择哪种,每款垃圾回收器都有自己的想法。

  值得注意的是,CMS中使用的增量更新,在重新标记阶段,除了需要遍历 写屏障的记录,还需要重新扫描遍历GC Roots(当然标记过的无需再遍历了),这是由于CMS对于astore_x等指令不添加写屏障的原因,具体可参考这里。


5.几种垃圾收集器对比及使用场景

收集器 年轻代 老年代 算法 适用场景
Serial 复制 Client 模式(桌面应用);单核服务器。可以用 -XX:+UserSerialGC 来选择 Serial 作为新生代收集器。
ParNew 复制 多核服务器;与 CMS 收集器搭配使用。当使用 -XX:+UserConcMarkSweepGC 来选择 CMS 作为老年代收集器时,新生代收集器默认就是 ParNew,也可以用 -XX:+UseParNewGC 来指定使用 ParNew 作为新生代收集器。
Parallel Scavenge 复制 注重吞吐量,高效利用 CPU,需要高效运算且不需要太多交互。可以使用 -XX:+UseParallelGC 来选择 Parallel Scavenge 作为新生代收集器,jdk7、jdk8 默认使用 Parallel Scavenge 作为新生代收集器。
Serial Old 标记-整理 Client 模式(桌面应用);单核服务器;与 Parallel Scavenge 收集器搭配;作为 CMS 收集器的后备预案。
Parallel Old 标记-整理 与Parallel Scavenge 收集器搭配使用;注重吞吐量。jdk7、jdk8 默认使用该收集器作为老年代收集器,使用 -XX:+UseParallelOldGC 来指定使用 Paralle Old 收集器。
CMS 标记-清除 重视服务器响应速度,要求系统停顿时间最短。可以使用 -XX:+UserConMarkSweepGC 来选择 CMS 作为老年代收集器。
G1 年轻代:复制
老年代:标记-整理
要求尽可能可控 GC 停顿时间;内存占用较大的应用。可以用 -XX:+UseG1GC 使用 G1 收集器,jdk9 默认使用 G1 收集器。

参考文章:
  官方文档
  G1详解

几种垃圾收集器对比及使用场景相关推荐

  1. JVM的7种垃圾收集器

    原文地址:Java虚拟机垃圾回收(三) 7种垃圾收集器 Java虚拟机垃圾回收(三) 7种垃圾收集器 主要特点 应用场景 设置参数 基本运行原理 在<Java虚拟机垃圾回收(一) 基础>中 ...

  2. 垃圾收集器回收种类 以及七种垃圾收集器

    垃圾收集器回收种类 垃圾收集器是垃圾回收算法的具体实现 串行垃圾回收器(Serial) 它为单线程环境设计且只使用一个线程进行垃圾回收,会暂停用户线程 (并行垃圾回收器)Parallel 多个垃圾收集 ...

  3. 深入理解7种垃圾收集器

    **如果说收集算法是内存回收的方法论,那么垃圾收集器就是内存回收的具体实现.**Java虚拟机规范中对垃圾收集器应该如何实现并没有任何规定,因此不同的厂商.版本的虚拟机所提供的垃圾收集器都可能会有很大 ...

  4. 深入理解JVM(3)——7种垃圾收集器

    如果说收集算法是内存回收的方法论,那么垃圾收集器就是内存回收的具体实现.Java虚拟机规范中对垃圾收集器应该如何实现并没有任何规定,因此不同的厂商.版本的虚拟机所提供的垃圾收集器都可能会有很大差别,并 ...

  5. jvm七种垃圾收集器

    JVM_七种垃圾收集器介绍 本文中的垃圾收集器研究背景为:HotSpot+JDK7 一.垃圾收集器概述 如上图所示,垃圾回收算法一共有7个,3个属于年轻代.三个属于年老代,G1属于横跨年轻代和年老代的 ...

  6. JVM的内存结构,Eden和Survivor比例;JVM中一次完整的GC流程,对象如何晋升到老年代,说说你知道的几种主要的JVM参数;CMS 常见参数解析;.你知道哪几种垃圾收集器,各自的优缺点

    47.JVM的内存结构,Eden和Survivor比例 49.JVM中一次完整的GC流程是怎样的,对象如何晋升到老年代,说说你知道的几种主要的JVM参数 50.-XX:+CMSScavengeBefo ...

  7. Java 的七种垃圾收集器

    了解 Java 中的内存管理. 用 C 或 C++ 这样的编程语言写一个应用时,需要编写代码来销毁内存中不再需要的对象.当应用程序扩展得越来越复杂时,未使用对象被忽略释放的可能性就越大.这会导致内存泄 ...

  8. JVM学习----七种垃圾收集器(GC)

    文章目录 GC垃圾收集器 七种经典的垃圾回收器 查看默认垃圾收集器 新生代 Serial垃圾收集器(单线程. 复制算法) ParNew 垃圾收集器 (Serial的多线程版本. 复制算法) Paral ...

  9. 七种垃圾收集器和垃圾回收、分代收集、GCROOTS相关概念、GC如何判断一个对象可以被回收

    文章目录 垃圾收集器概述 垃圾回收算法 1)标记-清除算法(Mark-Sweep)(DVM 使用的算法) 2)复制算法(Copying) 3)标记-整理算法(Mark-Compact) 4)分代收集( ...

最新文章

  1. [转] Java快速教程
  2. Angular中使用HttpClientModule模块实现get请求数据和post提交数据
  3. 一次MySQL性能优化实战(转)
  4. List 集合remove问题
  5. Linux进程命令PS用法笔记
  6. jdk8 参数为方法_JDK 8中的几乎命名的方法参数
  7. WebRTC 的现状和未来:专访 W3C WebRTC Chair Bernard Aboba
  8. 使用Varnish代替Squid做网站缓存加速器的详细解决方案
  9. SQL Server数据导入导出的几种方法
  10. Mcafee(麦咖啡)8.5i 使用设置图解
  11. 扩展欧几里得算法(简单易懂,详细分析)
  12. 扫描到pc服务器位置,打印机s2520 扫描到PC服务器之通讯录怎么设置
  13. MATLAB电机仿真精华50例
  14. 引流的最快方法是什么?我是如何实现长期被动引流的
  15. Davinci的异构多核间通信基础组件SysLink 2.0
  16. 端到端的图像压缩----《Joint Autoregressive and Hierarchical Priors for Learned Image Compression》 论文笔记
  17. Windows10系统部分软件出现中文乱码解决方法
  18. SVM(一):SVM入门
  19. java 四舍五入保留小数点后两位
  20. 微信小程序点击地址,跳转到地图导航

热门文章

  1. setState详解
  2. debian php-fpn_如何在基于 Ubuntu 或 Debian 的 Linux 发行版中查看一个软件包的依赖...
  3. 邓俊辉 数据结构 串
  4. Linux 串口编程(c++)
  5. 淘宝UWP桌面版已经发布
  6. 微信小程序日历签到组件(原创)
  7. (FJWC2020)DTOJ 4681. 楼房搭建
  8. 去他妈的月入100万
  9. 真会C#? -- Enumerator, Enumerable
  10. 如何正确使用redis