查看当前垃圾回收器类型命令
- java -XX:+PrintCommandLineFlags -version
- jps+jinfo:先使用jps查看java进程号,在使用jinfo查看该进程的配置
评估垃圾回收器性能时,重点关注吞吐量和暂停时间。
吞吐量和暂停时间是相互矛盾的,目前我们追求的效果是:在最大吞吐量优先的情况下,减小暂停时间。
吞吐量(Thoughput) :运行用户代码时间/(运行用户代码时间+垃圾收集时间)
比如程序运行100分钟,垃圾收集时间1分钟,吞吐量就是99%。
自适应调节策略:虚拟机会根据当前系统的运行情况收集性能监控信息,动态调整这些参数以提供最合适的停顿时间(-XX:MaxGCPauseMillis)或最大的吞吐量。该模式下,年轻代大小、伊甸园区和幸存者区的比例、晋升老年代的对象年龄阈值都会自动调整,以达到在堆大小、吞吐量和停顿时间之间的平衡点。
浮动垃圾:并发标记阶段,用户线程并未停止,该阶段也会产生垃圾, 回收器无法对这些垃圾进行标记,只能留到下次GC时处理。
垃圾回收器变更历史
1999年JDK 1.3.1 发布第一款串行方式的Serial GC,ParNew垃圾回收器是Serial回收器的多线程版本;
2002年2月26,Parallel GC和Concurrent Mark Sweep GC(CMS)跟随JDK 1.4.2一起发布;
Parallel GC在JDK 1.6后称为HotSpot默认GC;
2012年,在JDK 1.7u4版本中,G1可用;
2017年,JDK 9中,G1成为默认垃圾回收器,CMS被标记为过时;
2018年3月,JDK 10中提升G1并行性;
2018年9月,JDK 11引入了Epsilon垃圾回收器,同时引入ZGC(实验版本);
2019年3月,JDK 12发布,增强G1,并引入Shenandoah GC(实验版本);
2019年9月,JDK 13发布,增强ZGC;
2020年3月,JDK 14发布,删除CMS,拓展ZGC在MAC和Windows上的应用。
回收器类型对比
类型 | jvm开启参数 | 特性 |
---|---|---|
Serial、Serial Old | -XX:+UseSerialGC | 开启后: Serial(Young区用) + Serial Old(Old区用)的收集器组合:表示新生代、老年代都会使用串行回收收集器,新生代使用复制算法,老年代使用标记-整理/压缩算法。 SerialOld是运行在Client默认的java虚拟机默认的年老代垃圾收集器。Serial Old在Server模式下主要有两个用途:与新生代的Parallel Scavenge配合使用;作为老年代CMS回收器的后备垃圾收集方案。Serial适用于运行在Client模式下的虚拟机或者内存不大(几十MB到一两百MB)的环境下,因为是串行的,有较长时间的STW,所以并不适用于要求快响应、交互较强的应用。 |
ParNew收集器 | -XX:+UseParNewGC | 开启后,会使用: ParNew(Young区用) + Serial Old(Old区用)的收集器组合,新生代使用并发复制算法,老年代采用单线程标记-整理算法。 |
Parallel、 Parallel Old回收器 |
-XX:+UseParallelGC 或 -XX:+UseParallelOldGC | -XX:+UseParallelGC指定新生代使用Parallel Scavenge回收器;- XX:+UseParallelOldGC指定老年代使用Parallel Old回收器,它们是成对存在的,开启一个另一个也会开启。 新生代使用并发复制算法,老年代使用单线程标记-整理算法。 还可以通过-XX:ParallelGCThreads=设置并行回收器的线程数: 默认情况下,当CPU数量小于8个时,-XX:ParallelGCThreads=的值等于CPU数量; 当CPU数量大于8个,-XX:ParallelGCThreads=的值等于3+5*CPU_COUNT/8。 -XX:+UseAdaptiveSizePolicy开启Parallel Scavenge的自适应调节策略。 Parallel Scavenge为吞吐量优先,具有自适应调节策略的垃圾回收器。多用于在后台运算而不需要太多交互的任务 |
CMS(Concurrent Mark Sweep) | -XX:+UseConcMarkSweepGC | 优点:并发收集且并发清理;低延迟。 缺点:内存碎片,产生浮动垃圾,消耗CPU。 -XX:+UseConcMarkSweepGC,开启CMS GC,开启后作用于老年代,-XX:+UseParNewGC会自动打开; CMS作为一款老年代的垃圾回收器,不能和新生代垃圾回收器Parallel Scavenge搭配使用,只能和ParNew或者Serial搭配使用。 -XX:CMSInitiatingOccupanyFraction=,设置堆内存使用率阈值,一旦达到这个阈值,CMS开始进行回收(JDK5及之前,默认值为68,JDK6及以上版本默认值为92%); -XX:+UseCMSCompactAtFullCollection,指定在CMS回收完老年代后,对内存空间进行压缩处理,以避免碎片化问题; -XX:CMSFullGCsBeforeCompaction,设置执行多少次CMS GC后,对内存空间进行压缩整理; -XX:ParallelCMSThreads=,设置CMS的线程数。默认启动的线程数为(ParallelGCThreads+3)/4。我们知道,当CPU个数小于8时,ParallelGCThreads的默认值为CPU个数,所以对于一个8核CPU,默认启动的CMS线程数为3,换句话说只有62.5%的CPU资源用于处理用户线程。所以CMS不适合吞吐量要求高的场景。 |
G1收集器 | -XX:+UseG1GC | 面向服务端应用,响应优先。 优点: 1.并行与并发; 2.分代收集,可以采用不同的算法处理不同的对象; 3.空间整合,标记压缩算法意味着不会产生内存碎片; 4.可预测的停顿时间,能让使用者明确指定一个长度为M毫秒时间片段内,消耗在垃圾回收的时间不超过N毫秒(根据优先列表优先回收价值最大的region)。 缺点: 在小内存环境下和CMS相比没有优势,G1适合大的堆内存;在用户程序运行过程中,G1无论是为了垃圾回收产生的内存占用,还是程序运行时的额外执行负载都要比CMS高。 -XX:G1HeapRegionSize=,设置region的大小。值为2的幂,范围是1MB到32MB之间,目标是根据最小堆内存大小划分出约2048个区域。所以如果这个值设置为2MB,那么堆最小内存大约为4GB; -XX:MaxGCPauseMillis=,设置期望达到的最大GC停顿时间指标(JVM会尽力实现,但不保证达到),默认值为200ms; -XX:ParallelGCThread=,设置STW时GC线程数值,最多设置为8; -XX:ConcGCThreads=,设置并发标记的线程数,推荐值为ParallelGCThread的1/4左右; -XX:InitiatingHeapOccupancyPercent=,设置触发并发GC周期的Java堆占用率阈值,超过这个值就触发GC,默认值为45。 |
Shenandoah | -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC | Shenandoah stay G1以上的主要进展是在运行应用程序线程时完成更多的垃圾收集周期工作。G1只能在应用程序暂停(移动对象)时清空堆区域,Shenandoah可以在应用程序运行的同时重新定位对象。 为了实现并发重新定位,它使用了所谓的Brooks指针。指针是Shenandoah堆中的每个对象都有一个附加字段,它指向对象本身。Shenandoah这是因为,当它移动一个对象时,它还需要修复堆中引用该对象的所有对象。当Shenandoah将一个对象移动到一个新位置时,指针将保持在原来的位置,这会将引用转发到对象的新位置。引用对象时,应用程序将跟随指向新位置的前向指针。最后,需要清除带有前向指针的旧对象,但通过将清除操作与移动对象本身的步骤分离,Shenandoah更容易同时重新定位对象。 |
ZGC | -XX:+UnlockExperimentalVMOptions -XX:+UseZGC | ZGC允许Java应用程序继续运行,同时执行除线程堆栈扫描之外的所有其他垃圾收集操作。它可以从数百MB扩展到TB大小的Java堆,同时,始终保持非常低的暂停时间(通常在2毫秒以内)。适合于大型内存需求(例如,大数据)的应用程序。但是,对于需要可预测且极短暂停时间的较小堆,ZGC也是一个不错的选择。 |
G1回收器详解
G1适用于全堆,既可以在新生代使用和老年代使用。
G1收集器的设计目标是取代CMS收集器,它同CMS相比,在以下方面表现的更出色:
1、G1是一个有整理内存过程的垃圾收集器,不会产生很多内存碎片。
2、G1的Stop The World(STW)更可控,G1在停顿时间上添加了预测机制,用户可以指定期望停顿时间。
CMS垃圾收集器虽然减少了暂停应用程序的运行时间,但是它还是存在着内存碎片问题。于是,为了去除内存碎片问题,同时又保留CMS垃圾收集器低暂停时间的优点,JAVA7发布了一个新的垃圾收集器——G1垃圾收集器。
G1是在2012年才在jdk1.7u4中可用。 oracle官方计划在jdk9中将G1变成默认的垃圾收集器以替代CMS。它是一 款面向服务端应用的收器,主要应用在多CPU和大内存服务器环境下,极大的减少垃圾收集的停顿时间,全面提升服务器的性能,逐步替换java8以前的CMS
G1(Garbage First)回收器把堆内存分割成很多不相关的区域(region,物理上不连续),使用不同区域来表示伊甸园区,幸存者区和老年代。
G1会避免对整个Java堆进行垃圾收集,它会跟踪各个region里垃圾回收的价值大小(回收所获得的空间大小及所需时间的经验值),在后台维护一个优先列表,每次根据允许收集时间,优先回收价值最大的region。
region种类的说明:
E表示伊甸园区,S表示幸存者区、O表示老年代,空白表示未使用的内存区域;
一个region在同一时间内只能属于一种角色;
G1新增了一个全新的内存区域——Humongous,主要用于存放大对象。
G1回收垃圾过程主要分为以下几个步骤:
初始标记:仅仅是标记GC Roots能直接关联的对象,需要STW,但这个过程非常快;
并发标记:从GC Roots出发,对堆中对象进行可达性分析,找出存活对象,该阶段耗时较长,但是可与用户线程并发执行;
最终标记:主要修正在并发标记阶段因为用户线程继续运行而导致标记记录产生变动的那一部分对象的标记记录,需要STW;
筛选回收:将各个region分区的回收价值和成本进行排序,根据用户所期望的停顿时间制定回收计划。这阶段停顿用户线程,STW。