本文主要介绍了JVM的七种垃圾收集器(概要),通过示例代码进行了非常详细的介绍,对大家的学习或工作有一定的参考价值。有需要的朋友就跟着下面的边肖学习吧。
垃圾回收算法和垃圾回收器
JVM的垃圾收集算法包括复制算法、标签清理和标签排序。
用杨哥的话说,这些算法只是天上飞的想法,是一种方法论,但真正的垃圾收集还是要在地面上实现,于是垃圾收集器就应运而生了。
jvm的回收区包括方法区和堆,JVM根据不同区域的不同特点采用分代回收算法。比如因为所有的对象都分配在伊甸园区域,而且大部分存活时间都很短,都是“早晚死”,每一代新人存活下来的对象都不多,所以采用了新的复制算法。jvm默认情况下意味着新生代的对象要经过15 GC次才能进入老年期,所以老年期的对象生命周期长,采用标签清除或者标签排序算法。
那么这些算法的实现是怎样的呢?
新生代:连续,全新,平行
年龄:串行老,并行老,CMS
总计:G1
它们的搭配组合如下:
垃圾回收器
通常,jvm中有四种类型的垃圾收集器:串行、并行、并发(CMS)和G1。
串行垃圾回收器(Serial)
:专为单线程环境设计,只使用一个线程进行垃圾收集,会挂起所有用户线程。因此,它不适合服务器环境。并行垃圾回收器(Parallel)
:多个垃圾收集线程并行工作。此时用户线程暂停,适用于科学计算/大数据处理等弱交互场景。并发垃圾回收器(CMS)
:用户线程和垃圾收集线程同时执行(不一定并行,可以交替执行),不需要暂停用户线程。互联网被公司广泛使用,适合需要响应时间的场景。G1垃圾回收器
:G1垃圾收集器将堆内存划分为不同的区域,然后并发执行垃圾收集。默认的垃圾回收器
我们通常不配置任何jvm参数,程序可以正常执行。那么JVM默认的垃圾收集器是什么呢?
那么如何检查默认的回收器呢?方法有很多,这里仅举几个:
1.命令行模式:
Java-XX:PrintCommandLineFlags-version
您可以看到jdk8默认使用并行收集器。
2.jvm参数设置
还可以查看在JVM运行之前添加参数。其实这两种方式都差不多。
3.jps金佛
先用jps检查java进程号,再用jinfo检查进程的配置。
Serial收集器
Serial是单线程收集器,垃圾收集时必须停止所有工作(停止世界)。
串行收集器是最古老、最稳定和高效的收集器。它只使用一个线程来收集垃圾,但它可能会导致垃圾收集过程中的长时间暂停(
停止世界状态)。
虽然在垃圾收集的过程中需要暂停所有其他工作线程,但这是简单而高效的。对于单CPU环境,不需要线程交互的开销就可以达到最高的单线程垃圾收集效率,所以串行垃圾收集器仍然是运行在客户端模式下的java虚拟机默认的新一代垃圾收集器。
对应JVM参数是: -XX:+UseSerialGC
开启后会使用:* * serial(针对年轻区)serial old(针对老区)* *的收集器组合:表示新一代和老一代都会使用串行回收收集器,新一代使用复制算法,老一代使用标记-排序算法。
ParNew收集器
ParNew是Serial collector的升级版,将单线程垃圾收集升级为多线程垃圾收集,但依然停世界。
PAR收集器实际上是串行收集器的新一代并行多线程版本。最常见的应用场景是
配合老年代的CMS GC工作
,其余的行为和连环收藏家也是一模一样。ParNew垃圾收集器还必须在垃圾收集期间挂起所有其他工作线程。服务器上运行着大量的java虚拟机。
模式中新一代的默认垃圾收集器。
常用对应JVM参数: -XX:+UseParNewGC
启用ParNew collector只会影响新一代的收集,不会影响老一代的收集。
打开。以上参数后,将使用
ParNew(Young区用) + Serial Old
的收集器组合,新一代使用复制算法,老一代使用标记-排序算法。不过ParNew Tenured的组合,java8已经不推荐了。
Parallel收集器
并行清除收集器和ParNew一样,也是新一代垃圾收集器,使用复制算法,也是并行多线程垃圾收集器,俗称吞吐量。
数量优先级收集器。一句话:新一代和老一代串行采集器的并行化。
首先,科普下什么是吞吐量:
吞吐量(Thoughput)
=用户代码运行时间(用户代码运行时间垃圾收集时间),即例如程序运行100分钟,垃圾收集时间为1分钟。吞吐量为99%)。
并行收集器专注于:
可控制的高吞吐量意味着高效利用CPU的时间,它多用于在后台运算而不需要太多交互的任务。
* *自适应调节策略也是并联扫气收集器和ParNew收集器之间的一个重要区别。* *自适应调整策略:虚拟机根据当前系统运行情况收集性能监控信息,动态调整这些参数,以提供最合适的暂停时间(-XX:MaxGCPauseMillis)或最大吞吐量。
常用JVM参数: -XX:+UseParallelGC或-XX:+UseParallelOldGC(可互相激活)使用Parallel Scanvenge收集器
当该参数打开时:使用
Parallel收集器+Parallel Old
的组合。使用新一代复制算法,使用老一代标记-排序算法。Serial Old收集器
SerialOlid是串行垃圾收集器的老版本,也是单线程收集器。该收集器使用标记排序算法,主要运行在客户端。
java虚拟机默认的旧垃圾收集器。
在服务器模式下,主要有两个目的(知道版本已经到了8及以上):
1.它与JDK1.5之前版本的新一代并行清除收集器一起使用。(并行清除串行旧版本)
2.
作为老年代版中使用CMS收集器的后备垃圾收集方案
。Parallel Old收集器
并行旧收集器是并行清除的旧版本,使用多线程标记-排序算法。并行旧收集器仅在JDK1.6中提供。
在JDK1.6之前,新一代使用的并行扫气收集器只能和老一代的串行旧收集器匹配,只能保证新一代的吞吐量优先级,不能保证。
证书的总吞吐量。JDK1.6之前(并行清除串行旧)
并行旧只是给垃圾收集器提供旧代的吞吐量优先级。如果系统要求更高的吞吐量,JDK1.8之后可以优先考虑新一代。
并联扫气装置与老一代并联旧捕集器的配置策略。在JDK1.8和更高版本中(并行清除并行旧版本)
通用JVM参数:
-XX:+UseParallelOldGC
使用并联旧收集器。设置此参数后,新生代Parallel+老年代Parallel Old
。CMS(Concurrent Mark Sweep)
CMS收集器(Concurrent Mark Sweep: 并发标记清除)是一种以获取最短回收停顿时间为目标的收集器
。适用于互联网网站或B/S系统的服务器。这类应用特别注重服务器的响应速度,希望系统停顿时间最短。
CMS非常适合堆内存大、CPU核多的服务器端应用,在G1出现之前也是大型应用的首选收集器。
并发标记清除清除并发标记,收集低暂停并发数据,并使用用户线程执行。
启动这个收集器的JVM参数:
-XX:+UseConcMarkSweepGC
。当这个参数打开时,-XX: UseParNewGC将自动打开。当此参数打开时,将使用
ParNew(Young区用) + CMS(Old区用) + Serial Old
的收集器组合,并且Serial Old将用作CMS错误的备份收集器。CMS收集器的运行过程分为下列4步:
* *初始标记:* *标记GC根可以直接关联的对象。它很快,但是世界停止了。
* *并发标记:* *遍历GC根追踪的过程,找出幸存的对象和用户线程可以并发执行。
* *重新打标:* *为了修正一部分对象的打标记录,这些对象在并行打标时由于用户程序的连续运行而导致打标发生变化。仍然有停止世界的问题。
* *并发清除:* *清除并回收标记的对象。
**CMS优势:* *低暂停的并发收集
缺点:
1.浮动垃圾:由于用户线程还在CMS并发清理阶段运行,自然会随着程序的运行产生新的垃圾。在这部分垃圾被标记后,CMS无法在当前的集合中处理它,所以它必须等待下一个GC来清理它。这部分垃圾叫做漂浮垃圾。在jdk1.5的默认设置下,在老年期使用68%的空间时会激活CMS收集器,触发百分比可以增加-xx: cmsinialoccupancyfraction的值。在jdk1.6中,CMS启动阈值提高到92%。如果CMS运行过程中预留的内存不能满足程序的需要,就会出现“并发模式失败”,然后串行旧收集器就会降级,在旧时代临时启用垃圾收集,所以暂停时间会很长。因此-xx: cmsinialoccupancyfracture的高设置很容易导致大量的“并发模式失败”。
2.有空间碎片:CMS是基于“标记-清除”算法实现的,所以会产生空间碎片。为了解决这个问题,CMS提供了开发参数-xx:usecmscompactfullcollection来启动内存碎片的合并。因为记忆巩固不能并行,停顿时间会更长。还有-xx: cmsfullgcbeforecompression,用来设置Full GC不压缩的次数,后面跟一个带压缩的(默认为0)。
3.对CPU资源敏感。虽然在并发标记和并发清理阶段不会停止用户线程,但是会因为垃圾收集占用了部分cpu资源而使用户程序变慢。
CMS启动的回收线程的默认数量是(cpu数量3)/4。所以CPU数量少会导致用户程序的执行速度慢很多。
G1收集器
G1适用于整个反应堆,新生代和老龄都可以使用。G1与以往的收藏家非常不同,它是从不同的角度设计的。
回想一下以前的垃圾收集器的特征:
1.年轻一代和老一代是独立的、连续的记忆块。
2.从到的年轻一代伊甸使用复制算法
3.老年的收藏必须扫描老年的所有记忆空间。
4.设计原则是尽可能少而快地执行GC。
G1收集器旨在取代CMS收集器。与CMS收集器相比,G1收集器在以下几个方面表现更好:
1.G1是一个带有内存排序过程的垃圾收集器,不会产生很多内存碎片。
2.G1的《停止世界》( STW)更可控。G1为暂停时间添加了预测机制,用户可以指定预期的暂停时间。
虽然CMS垃圾收集器减少了暂停应用程序的运行时间,但它仍然存在内存碎片的问题。因此,为了消除内存碎片问题,同时保留
利用CMS垃圾收集器的低暂停时间,JAVA7发布了新的垃圾收集器——G1垃圾收集器。
G1在2012年只有jdk1.7u4版本。Oracle官方计划让G1成为jdk9中的默认垃圾收集器,以取代CMS。它是面向服务的应用程序。
Server,主要用于多CPU、大内存的服务器环境,大大减少垃圾收集的暂停时间,全面提升服务器的性能,逐渐取代java8之前的CM:
收藏家。
主要变化是
Eden,Survivor和Tenured等内存区域不再是连续的了,而是变成了一个个大小一样的region ,每个region从1M到32M不等。- - 个region有可能属于Eden, Survivor或 者Tenured内存区域。
。底层原则
G1最大的优点是可以分块,避免全内存扫描,只按区域扫描。
G1收集器大致可以分为以下几个步骤:
* *初始标记:* *只标记GC根可以直接到达的对象,并修改TAMS的值(标记开始时的下一个Top),以便下一个用户程序并发运行时,可以在正确的可用区域创建新的对象。(需要线程暂停,但是需要很短的时间。)
* *并发标记:* *从GC根开始分析堆中对象的可达性,找出幸存的对象。(需要很长时间,但可以与用户程序同时执行)
* *最终打标:* *为了纠正打标记录中因同时打标时执行用户程序而发生变化的部分。将对象的变化记录在线程记忆集日志中,并将记忆集日志中的数据合并到记忆集中。(需要线程暂停,但可以并行执行。)
* *筛选回收:* *对各区域的回收价值和成本进行排序,根据用户期望的GC暂停时间制定回收计划。(可以同时执行)
总结
关于JVM的七种垃圾收集器的这篇文章到此为止。有关JVM垃圾收集器的更多信息,请搜索我们以前的文章或继续浏览下面的相关文章。希望大家以后能多多支持我们!