北京私人做网站,台州网站排名外包,大连在哪个省份哪个市,茂名网站优化垃圾收集器 文章目录 各收集器简单对比收集器启动参数各收集器详细说明JDK 1.3 之前JDK 1.3 | SerialJDK 1.4 | ParNewJDK 1.4 | Parallel ScavengeJDK 5 | CMS 收集器JDK 7 | G1 各收集器简单对比
收集器名称出现时间淘汰时间目标采用技术线程数STW分代备注无名JDK 1.3之前JD…垃圾收集器 文章目录 各收集器简单对比收集器启动参数各收集器详细说明JDK 1.3 之前JDK 1.3 | SerialJDK 1.4 | ParNewJDK 1.4 | Parallel ScavengeJDK 5 | CMS 收集器JDK 7 | G1 各收集器简单对比
收集器名称出现时间淘汰时间目标采用技术线程数STW分代备注无名JDK 1.3之前JDK 1.3无标记清除1是不分代SerialJDK 1.3至今仍作为客户端默认的收集器无标记复制1是新生代/老年代由于简单而高效仍作为客户端系统的默认垃圾收集器。ParNewJDK 1.4自JDK9开始只能与CMS搭配只用高效的回收垃圾标记复制默认与核心线程数一样多是新生代可以看做是Serial的多线程版本Parallel ScavengeJDK 1.4至今仍活跃尤其是需要吞吐量的场景如大量计算等最大吞吐量标记复制默认与核心线程数一样多是新生代吞吐量优先收集器吞吐量需满足下方公式CMSJDK 5JDK9标记为过时/JDK14被正式移除最短回收停顿时间标记清除(处理器核心数量3)/4否老年代第一个可以与用户线程同时工作的垃圾收集器工作时长更长了但是用户线程停顿更短饿了Serial Old不明确/1.2之前JDK之前与Parallel Scavenge现在一般作为CMS失败的备用方案无标记整理1是老年代Serial的老年版Parallel OldJDK 6至今最大吞吐量标记整理N是老年代Parallel Scavenge的老年斑G1/Garbage FirstJDK 7至今时间可控/全功能标记复制N是Region分区G1淘汰了CMSShenandoahOpenJDK 12至今10毫秒内垃圾收集标记整理N否Region分区RedHat开发JDK中没有只有OpenJDK中才有ZGCJDK 11至今10毫秒内垃圾收集标记整理N否Region分区使用了读屏障、染色指针和内存多重映射等技术 名词解释STWStop The World指停止用户线程该值为否则表示可以与用户线程同时进行。也许不是整个清理阶段都与用户线程并行可能只是其中某些阶段 吞吐量 运行用户代码时间 运行用户代码时间 运行垃圾收集时间 吞吐量{运行用户代码时间\over{运行用户代码时间运行垃圾收集时间}} 吞吐量运行用户代码时间运行垃圾收集时间运行用户代码时间 收集器启动参数
在本部分中有一些启动项目的命令这里采用Github开源项目·Zfile进行示例。
收集器名称启动该收集器Serial-XX:UseSerialGCParNew-XX:UseParNewGCParallel Scavenge-XX:UseParallelGCCMS-XX:UseConcMarkSweepGCSerial Old使用Serial收集器时会自动启动Serial Old收集器Parallel Old-XX:UseParallelOldGCG1/Garbage First-XX:UseG1GCShenandoah-XX:UnlockExperimentalVMOptions -XX:UseShenandoahGC # Serial
java -XX:UseSerialGC -jar zfile.jar# ParNew
java -XX:UseParNewGC -jar zfile.jar # ParNew CMS
java -XX:UseConcMarkSweepGC -XX:UseParNewGC -jar zfile.jar# Parallel Scavenge
java -XX:UseParallelGC -jar zfile.jar
java -XX:UseParallelGC -XX:GCTimeRatio1 -jar zfile.jar # 垃圾收集器占比不超过1%
java -XX:UseParallelGC -XX:UseAdaptiveSizePolicy -jar zfile.jar # 虚拟机优化内存# CMS
java -XX:UseConcMarkSweepGC -jar zfile.jar# Parallel Old收集器
java -XX:UseParallelOldGC -jar zfile.jar# G1
java -XX:UseG1GC -jar zfile.jar# Shenandoah | 由于现在还在测试阶段需要使用 -XX:UnlockExperimentalVMOptions
java -XX:UnlockExperimentalVMOptions -XX:UseShenandoahGC -jar zfile.jar各收集器详细说明 JDK 1.3 之前
JDK 1.3 之前并没有一个真正像样的垃圾收集器据说Serial Old是1.2之前出现的其余不详那个时代的垃圾收集器甚至没有一个名字资料只能搜索到“标记-清除垃圾收集器”很明显是基于标记清除算法实现的特点是单线程需要停止用户线程没有分代效率低下等… JDK 1.3 | Serial
Serial收集器采用标记-清除算法单线程处理在进行垃圾收集的时候必须停止用户线程(STW/Stop The World)Serial收集的比较“慢”这也是一开始都诟病Java慢的主要原因。
但是Serial的优点是简单它不需要太多的内存空间也没有线程切换的资源消耗就像是一个扫地僧一样默默地进行着自己的工作。而且虽然“慢”但是一般来说也就只有几十~上百毫秒虽然这个时间对于服务端程序来说可能十分宝贵但是对于客户端程序来说无伤大雅可能你使用的Java App一直每隔一段时间暂停几十毫秒而你根本察觉不到。正是由于它简单不消耗太多内存等高效相对于其它多线程版本的一条线程来说所以Serial被广泛使用在客户端程序中。
Serial收集器的工作过程如下图片来源于《深入理解Java虚拟机》 可以看出每次需要进行垃圾收集的时候都需要停顿用户线程且每次只有一个线程在进行垃圾收集 JDK 1.4 | ParNew
ParNew收集器是Serial收集器的多线程版本在操作上除了是采用多线程的方式来进行的以外其余与Serial区别不大。需要注意的是由于ParNew还需要有现成切换的成本所以其单线程的效率是比Serial低的也就是说核心数为1时其工作效率不如Serial收集器。
所以ParNew收集器更适合于核心线程数尚且客观4~6个的一些老项目中。 JDK 1.4 | Parallel Scavenge
吞吐量公式说明
Parallel Scavenge是一款吞吐量收集器主要关注程序的吞吐量首先了解下吞吐量计算公式: 吞吐量 运行用户代码时间 运行用户代码时间 运行垃圾收集时间 吞吐量{运行用户代码时间\over{运行用户代码时间运行垃圾收集时间}} 吞吐量运行用户代码时间运行垃圾收集时间运行用户代码时间
如果程序运行需要99毫秒垃圾回收需要1毫秒那么吞吐量就是 99/(1 99) 99%。
相关参数
我们可以通过下面一些指令来控制吞吐量也可以直接控制最大垃圾收集停顿时间等或者直接将这些参数交给虚拟机来进行控制。
指令接收参数说明-XX:MaxGCPauseMillis大于0的毫秒数控制最大垃圾收集停顿时间-XX:GCTimeRatio大于0小于100的整数也就是垃圾收集时间占总时间的比率直接设置吞吐量大小-XX:UseAdaptiveSizePolicy允许虚拟机自动对内存进行调优从而控制吞吐量 JDK 5 | CMS 收集器
CMS简介
CMS收集器是一种以获取最短回收停顿时间为目标的收集器。目前很大一部分的Java应用集中在互联网网站或者基于浏览器的B/S系统的服务端上这类应用通常都会较为关注服务的响应速度希望系统停顿时间尽可能短以给用户带来良好的交互体验。CMS收集器就非常符合这类应用的需求。
CMS收集器采用标记清除算法其工作分为四个步骤 初始标记初始标记仅仅只是标记一下GC Roots能直接关联到的对象速度很快 并发标记(CMS concurrent mark) 与用户线程同时并发标记阶段就是从GC Roots的直接关联对象开始遍历整个对象图的过程这个过程耗时较长但是不需要停顿用户线程可以与垃圾收集线程一起并发运行 重新标记(CMS remark)重新标记阶段则是为了修正并发标记期间因用户程序继续运作而导致标记产生变动的那一部分对象的标记记录这个阶段的停顿时间通常会比初始标记阶段稍长一些但也远比并发标记阶段的时间短 并发清除(CMS concurrent sweep) 与用户线程同时最并发清除阶段清理删除掉标记阶段判断的已经死亡的对象由于不需要移动存活对象所以这个阶段也是可以与用户线程同时并发的
并发清除一定会面临两个问题浮动垃圾与消失对象问题CMS采用的是增量更新的解决方案在之前的博客中已经介绍过了请点此查看。 CMS的缺点 **处理器资源敏感**CMS默认启动的回收线程数是处理器核心数量3/4也就是说如果处理器核心数在四个或以上并发回收时垃圾收集线程只占用不超过25%的处理器运算资源并且会随着处理器核心数量的增加而下降。但是当处理器核心数量不足四个时CMS对用户程序的影响就可能变得很大。如果应用本来的处理器负载就很高还要分出一半的运算能力去执行收集器线程就可能导致用户程序的执行速度忽然大幅降低 Full GC问题由于CMS收集器无法处理“浮动垃圾”(Floating Garbage)有可能出现“Concurrent Mode Failure”失败进而导致另一次完全“Stop The World”的Full GC的产生我的理解是由于浮动垃圾的存在导致浪费了一定的空间并且垃圾收集过程中用户线程还在继续还在产生新的垃圾最终内存空间不足导致直接触发FullGC。因此CMS一般会在内存空间达到一定阈值后直接进行垃圾回收JDK5默认是68%JDK6默认为92%可以通过-XX:CMSInitiatingOccupancyFraction调整阈值大小。 空间碎片问题由于CMS是基于标记清除算法进行工作的这意味着收集结束时会有大量空间碎片产生。空间碎片过多时将会给大对象分配带来很大麻烦往往会出现老年代还有很多剩余空间但就是无法找到足够大的连续空间来分配当前对象而不得不提前触发一次Full GC的情况。 CMS运行示意图 JDK 7 | G1 G1收集器具有里程碑式意义它开创了收集器面向局部收集的设计思路和基于Region的内存布局形式。简单来说传统的垃圾收集器都是一个老年代一个新生代老年代用来存放存活时间较长的对象或一些大对象新生代用来存放新对象。而G1收集器采用的是 在G1收集器出现之前的所有其他收集器包括CMS在内垃圾收集的目标范围要么是整个新生代(Minor GC)要么就是整个老年代(Major GC)再要么就是整个Java堆(Full GC)。而G1跳出了这个樊笼它可以面向堆内存任何部分来组成回收集Collection Set一般简称CSet进行回收衡量标准不再是它属于哪个分代而是哪块内存中存放的垃圾数量最多回收收益最大这就是G1收集器的Mixed GC模式。 简单来说G1收集器不再是传统的老年代与新生代而是将连续的Java堆划分为多个大小相等的独立区域Region每一个Region都可以根据需要扮演老年代、新生代的角色。G1收集器会根据 Region是最小的的单位每次垃圾收集的内存空间一定是Region的整数倍。G1会根据回收收益情况判断回收哪些Region空间。 Region中还有一类特殊的Humongous区域**专门用来存储大对象。**G1认为只要大小超过了一个Region容量一半的对象即可判定为大对象。每个Region的大小可以通过参数-XXG1HeapRegionSize设定取值范围为1MB32MB且应为2的N次幂。而对于那些超过了整个Region容量的超级大对象将会被存放在N个连续的Humongous Region之中G1的大多数行为都把Humongous Region作为老年代的一部分来进行看待。 产生的问题与解决方案
**跨区引用问题**每个Region都维护有自己的记忆集这些记忆集会记录下别的Region指向自己的指针并标记这些指针分别在哪些卡页的范围之内。G1的记忆集在存储结构的本质上是一种哈希表Key是别的Region的起始地址Value是一个集合里面存储的元素是卡表的索引号。这种“双向”的卡表结构卡表是“我指向谁”这种结构还记录了“谁指向我”比原来的卡表实现起来更复杂同时由于Region数量比传统收集器的分代数量明显要多得多因此G1收集器要比其他的传统垃圾收集器有着更高的内存占用负担。
**收集线程与用户线程互不干扰的运行:**首先要解决的是用户线程改变对象引用关系时必须保证其不能打破原本的对象图结构导致标记结果出现错误见《HotSpot实现细节-原是快照》;此外垃圾收集对用户线程的影响还体现在回收过程中新创建对象的内存分配上程序要继续运行就肯定会持续有新对象被创建G1为每一个Region设计了两个名为TAMS(Top at Mark Start)的指针把Region中的一部分空间划分出来用于并发回收过程中的新对象分配并发回收时新分配的对象地址都必须要在这两个指针位置以上。G1收集器默认在这个地址以上的对象是被隐式标记过的即默认它们是存活的不纳入回收范围。与CMS中的“Concurrent Mode Failure”失败会导致Full GC类似如果内存回收的速度赶不上内存分配的速度G1收集器也要被迫冻结用户线程执行导致Full GC而产生长时间“Stop The World”。
**怎样建立起可靠的停顿预测模型**用户通过-XXMaxGCPauseMillis参数指定的停顿时间只意味着垃圾收集发生之前的期望值但G1收集器要怎么做才能满足用户的期望呢G1收集器的停顿预测模型是以衰减均值(Decaying Average)为理论基础来实现的在垃圾收集过程中G1收集器会记录每个Region的回收耗时、每个Region记忆集里的脏卡数量等各个可测量的步骤花费的成本并分析得出平均值、标准偏差、置信度等统计信息。这里强调的“衰减平均值”是指它会比普通的平均值更容易受到新数据的影响平均值代表整体平均状态但衰减平均值更准确地代表“最近的”平均状态。换句话说Region的统计状态越新越能决定其回收的价值。然后通过这些信息预测现在开始回收的话由哪些Region组成回收集才可以在不超过期望停顿时间的约束下获得最高的收益。 回收过程 **初始标记(Initial Marking)**仅仅只是标记一下GC Roots能直接关联到的对象并且修改TAMS指针的值让下一阶段用户线程并发运行时能正确地在可用的Region中分配新对象。这个阶段需要停顿线程但耗时很短而且是借用进行Minor GC的时候同步完成的所以G1收集器在这个阶段实际并没有额外的停顿。 **并发标记(Concurrent Marking)**从GC Root开始对堆中对象进行可达性分析递归扫描整个堆里的对象图找出要回收的对象这阶段耗时较长但可与用户程序并发执行。当对象图扫描完成以后还要重新处理SATB记录下的在并发时有引用变动的对象。 **最终标记(Final Marking)**对用户线程做另一个短暂的暂停用于处理并发阶段结束后仍遗留下来的最后那少量的SATB记录。 **筛选回收(Live Data Counting and Evacuation)**负责更新Region的统计数据对各个Region的回收价值和成本进行排序根据用户所期望的停顿时间来制定回收计划可以自由选择任意多个Region构成回收集然后把决定回收的那一部分Region的存活对象复制到空的Region中再清理掉整个旧Region的全部空间。这里的操作涉及存活对象的移动是必须暂停用户线程由多条收集器线程并行完成的。