垃圾收集器

it2022-05-06  1

Serial收集器(单线程)

Serial(串行)收集器是最近本、发展历史最悠久的收集器,曾经(JDK1.3之前)是虚拟机新声代收集的唯一选择。 这是一个单线程收集器。它的“单线程”的意思并不仅仅说明它只会使用一个CPU或一条收集线程去完成垃圾收集工作,更重要的是它在进行垃圾回收是,必须暂停其他所有的工作线程(Stop The World),直到它收集结束。 新生代采用复制算法,老年代采用标记-整理算法。

优于其他收集器的地方

简单高效(于其他收集器的单线程相比):对于限定单个CPU的环境来说,Serial收集器由于没有线程交互的开销,专心做垃圾收集自然可以获得最高的单线程收集效率。Seiral收集器对于运行在Client模式下的虚拟机来说是个不错的选择

ParNew收集器(多线程)

ParNew收集器是Serial收集器的多线程版本,除了使用多条线程进行垃圾收集之外,其余行为保罗Serail收集器可用的所有控制参数、收集算法、Stop The World、对象分配规则、回收策略等都与Serial收集器完全一样 新生代采用复制算法,老年代采用标记-整理算法 它是许多运行在Server模式下的虚拟机的首要选择,除了Serial收集器外,只有它能与CMS收集器(真正意义上的并发收集器)配合工作。 可以使用:-XX:ParNewGC选项来强制指定它。 可以使用:-XX:ParallelGCThreads 参数来限制垃圾收集器的线程数

Parallel Scavenge收集器(多线程)

Parallel Scavenge收集器是一个新生代收集器,它也是使用复制算法的收集器,又是并行的多线程收集器,看上去和ParNew一样,那他有什么特别指之处:

Parallel Scavenge 收集器的关注的是吞吐量(高效利用CPU,也叫“吞吐量优先”收集器),CMS等垃圾收集器的关注点是尽可能地缩短垃圾收集时用户线程的停顿时间。所谓吞吐量就是CPu用于运行用户代码额时间与CPU总耗时的比值,即吞吐量=运行用户代码时间/(运行用户代码时间+垃圾收集时间)

停顿时间越短就越适合需要与用户交互的程序,良好的响应速度能提升用户体验,而高吞吐量可以高效利用CPU时间,尽快完成程序的运算任务,主要适合在后台运算而不需要太多交互的任务。

Parallel Scavenge 收集器提供了两个参数用于精确控制吞吐量

-XX:MaxGCPausuMillis:设置最大垃圾收集停顿时间-XX:GCTimeRatio:设置吞吐量大小 Parallel Scavenge GC停顿时间的缩短是以牺牲吞吐量和新生代空间来换取的:系统把新生代调小一点,收集时间会快一点,但是也只直接导致垃圾收集发生的更频繁一些。停顿时间在下降,但是吞吐量也降下来了。 -XX:AdaptiveSizePolicy :打开后虚拟机会根据当前系统的运行情况收集性能监控信息,动态调整一些参数以提供最合适的停顿时间或者最大的吞吐量。称为GC自适应的调节策略。 -XX:+UseParallelGC :使用 Parallel 收集器+ 老年代串行 -XX:+UseParallelOldGC:使用 Parallel 收集器+ 老年代并行

新生代采用复制算法,老年代采用标记-整理算法

Serial Old收集器(单线程)

是Serial收集器的老年代版本,它同样是一个单线程收集器,使用“标记-整理”算法。这个收集器的主要意义也是在于给Client模式狭隘的虚拟机使用。 它主要有两大用途:一种用途是在JDK1.5及以前的版本中与Parallel Scavenge 收集器搭配使用,另一种用途是作为CMS收集器的后备方案。

Parallel Scavenge收集器架构中本身有PS MarkSweep收集器来哦进行老年代收集,并非直接使用了Serial Old收集器,但是这个PS MarkSweep收集器与Serial Old实现非常接近,所以砸在官方的许多资料中都是直接以Serial Old代替PS MarkSweep进行讲解

Parallel Old收集器(多线程)

Parallel Old是Parallel Scavenge收集器的老年代版本,使用多线程和“标记-整理”算法。在JDK1.6中开始提供。 在此之前新生代的Parallel Scavenge只能与Serial Old协作。由于老年代 Serial Old收集器在服务端应用性能上的“拖累”,使用了Parallel Scavenge收集器也未必能在整体应用上获得吞吐量最大化的效果,由于单线程的老年代收集中无法充分利用服务器多CPU的处理能力,在老年代很大而且硬件比较高级的环境中,这种组合的吞吐量甚至不一定有ParNew加CMS的组合给力。

CMS收集器

CMS(Concurrent Mark Sweep)收集器是一种以获得最短收集挺淡时间为目标的收集器。它非常符合在注重用户体验的应用上使用。在垃圾收集时,用户线程和GC线程并发执行,因此在垃圾收集过程中用户也不会感到明显的卡顿 CMS收集器是基于“标记-清除”算法实现的,它的运作过程分为4个步骤: 初始标记(CMS initial mark):stop the world 仅仅标记一下GC Roots能直接关联到的对象,很快 并发标记(CMS concurrent mark):进行GC RootsTracing的过程。使用多条标记线程,与用户线程并发执行。此过程进行可达性分析,标记处所有废弃对象。速度慢。 重新标记(CMS remark):stop the world 是为了修正并发标记期间因用户程序继续运作而导致标记产生变动的那一部分对象的标记记录(将并发标记过程中新出现的飞起对象标记出来)。停顿时间 :初始标记<重新标记<并发标记 并发清除(CMS concurrent sweep):只使用一条GC线程,与用户线程并发执行,清除刚才标记的对象。这个过程非常耗时。

是一款优秀的收集器。主要优点:并发收集、低停顿。(也被称为并发低停顿收集器) 但是它有三个主要缺点:

对CPU资源非常敏感:(面上并发设计的程序都对CPU资源比较敏感)会占用一部分线程(或者说CPU资源)而导致应用程序变慢,总吞吐量下降。默认启动的回收线程数是(CPU资源+3)/4,随着CPu数目增加而减少,但是当CPU不足4个,影响就比较大,必须要分出一半CPU运算能力去执行收集器线程。无法处理浮动垃圾。要是CMS运行期间预留的内存无法满足程序需要,就会出现一次“Concurrent Mode Failure‘失败而导致另一次Full GC的产生。它使用的回收短发“标记-清除”算法会导致收集结束时会有大量空间碎片产生。

对于产生碎片空间这个问题,可以通过开启(默认开启)-XX:UseCMSCompactFullCollection,在每次Full GC完成后都会进行一次内存压缩整理,将零散在各处的对象整理到一块。设置参数-XX:CMSFullGCsBeforeCompaction,告诉CMS经过N次Full GC之后在进行一次内存整理(默认0,表示每次进入Full GC时都进行碎片整理)

G1收集器

G1(Garbage-First)收集器是当今收集器技术发展的最前沿成果之一。是一款面向服务端应用的垃圾收集器。HotSpot开发团队希望未来它可以替换掉JDK1.5中发布的CMS收集器。 他没有新生代和老年代的概念,而是将对划分为一块块独立的Regin。当要进行垃圾收集时,首先估计每个Regin中垃圾的数量,每次都从垃圾回收价值最大的Region开始回收,因此可以获得最的回收效率。 从整体上看,G1时基于“标记-整理”算法实现的收集器,从局部(两个Region之间)上看是基于“复制”算法实现的,这意味着运行期间不会产生内存空间碎片,收集后能提供规整的可用内存。这有利于程序长时间运行,分配大对象时不会因为无法找到连续的内存空间而提前出发下一次GC。

它具备如下特点:

并行与并发:G1能充分利用CPU、多核环境下的硬件优势,使用多个CPU来缩短Stop The World停顿时间。部分其他收集器原本需要停顿Java线程执行的GC动作,G1收集器仍然可以通过并发的方式让Java程序继续执行。分代收集:虽然G1可以不需要其他收集器配合就能独立管理整个GC堆,但是还是保留了分代的概念空间整合:与CMS的“标记-清理”算法不同,G1从整体来看是基于“标记-整理”算法实现的收集器;从局部上来看是基于“复制”算法实现的。可预测的停顿:这是G1相对于CMS的另一个大优势,降低停顿时间是G1和CMS共同关注的店,但G1除了追求低停顿外,还能建立可预测的停顿时间模型,能让使用者明确指定一个长度为M毫秒的时间片段内。

G1收集器的运作大致分为以下几个步骤

初始标记并发标记最终标记筛选回收

G1 收集器在后台维护了一个优先列表,每次根据允许的收集时间,优先选择回收价值最大的 Region(这也就是它的名字 Garbage-First 的由来)。这种使用 Region 划分内存空间以及有优先级的区域回收方式,保证了 GF 收集器在有限时间内可以尽可能高的收集效率(把内存化整为零)。


最新回复(0)