垃圾算法与回收
-
一、垃圾回收算法
-
1.1)标记清除算法:
先将需要回收的对象进行标记,标记完成后统一回收所有标记的对象;标记清除算法是最基础的收集算法;
明显的问题:
效率没有复制算法高;
空间问题,标记清除后会产生大量不连续的碎片,散乱,存在不能在放置一块连续的对象;
-
1.2)复制算法:
是“标记清除算法”的升级版,解决效率及碎片问题。将需要清理的内存分为大小相同的两块(原内存,保留内存),根据GCRoot根查找到存活的对象,将存活对象直接连续性的放入保留内存中,讲原内存空间一次清理掉;
问题:空间利用率存在问题;
这里需要注意:复制算法仅适用于年轻代;这里也可以理解年轻代里分为Eden、From、To区域的原因;
-
1.3)标记整理算法:
根据老年代的特点特别退出的一种标记算法,现将垃圾对象进行标注,将未标记的存活对象整理成连续的内存,最后将所有垃圾对象进行回收;
-
1.4)分代收集算法:
根据老年代与年轻代不同的特点,选择不同的算法;
-
二、垃圾收集器
垃圾收集算法是理论,垃圾收集器是垃圾收集算法的实现;
垃圾收集器是需要根据不同的场景进行分析然后再选型的,没有最牛逼、通用的,只有适合的;
-
2.1)Serial收集器
顾名思义,是一个单线程收集器,是一个历史悠久的收集器;开始执行的时候会暂停应用程序的线程,直到收集处理完成后才会回复应用程序线程;
Serial Old收集器是Serial收集器的老年代版本,也是一个单线程收集器;
特别说明:是CMS收集器的备选方案;
对于新生代使用的是复制算法,老年代使用的是标记整理算法;
开启参数:-XX:+UseSerialGC -XX:+UseSerialOldGC
-
2.2)ParNew收集器
是“Serial收集器”的多线程版本,默认的手机线程数跟CPU核数相同;
注意:可以使用-XX:ParallelGCThreads参数指定收集线程数,但是这样风险会非常高,没有深入JVM底层原理的小白请不要乱动,否则后果自负;
开启参数:-XX:+UseParNewGC
-
2.3)Parallel Scavenge收集器
类似于ParNew收集器,是Server模式(内存大于2G,2个CPU)下的默认收集器;
关注吞吐量,高效的利用CPU,所谓的吞吐量就是CPU中用于运行用户代码的时间与CPU总消耗时间比;
在对于收集器运作不太了解情况下,把内存管理优化交给虚拟机去完成也是一个不错的选择;
对于新生代使用的是复制算法,老年代使用的是标记整理算法;
Parallel Old是Parallel Scavenge收集器的老年代版本。使用多线程和标记整理算法,在注重吞吐量以及CPU资源的场合,可以优先考虑Parallel Scavenge和Parallel Old收集器;
-
2.4)CMS收集器(只能用在老年代)
是一种以获得最短回收停顿时间为目标的收集器。非常注重用户体验的应用上使用,他是HotSpot虚拟机第一款真正意义上的并发收集器,实现了让垃圾收集线程与用户线程(基本上)同时工作;
CMS收集器是“标记清除算法“的实现,分为以下几个步骤:
1、初始标记:暂停所有的其他线程,并记录GC Roots直接引用的对象,速度很快;
2、并发标记:同时开启GC和用户线程,用一个闭包结构(整个内存中的所有GC Roots及所有的跟——全链路标记)记录可达性对象,但是在这个阶段结束后,这个闭包结构并不能保证包含当前所有的可达对象,因为是多线程,用户线程也在进行,可能会改变更新引用区域。所以这个算法里会根据记录这些发生引用更新的地方;
占用整个GC阶段的70-80%时间
3、重新标记:暂停所有其他的线程修正并发标记期间因为用户线程运行而导致标记变动的记录。这个阶段停顿的时间一般会比初始标记的时间稍微长一点,但远远低于并发标记的时间;
4、并发清理:开启用户线程,GC线程,GC线程开始对未标记的区域做回收工作;
优点:
并发收集,低停顿;
缺点:
和服务抢占CPU资源;
无法处理浮动垃圾,只有在下次GC才能备清理;
是”标记-清除“所以会有大量的空间碎片;
执行过程中不确定性,会存在上一次垃圾还没有执行完,然后垃圾回收又被触发,也就是:并发模式失败(concurrent mode failure)。此时进入”stop the world“ 而改用Serial old单线程收集器来进行回收;
可用配套参数
1. -XX:+UseConcMarkSweepGC:启用cms
2. -XX:ConcGCThreads:并发的GC线程数,但不建议配置
3. -XX:+UseCMSCompactAtFullCollection:FullGC之后做压缩整理(减少碎片)
4. -XX:CMSFullGCsBeforeCompaction:多少次FullGC之后压缩一次,默认是0,代表每次
FullGC后都会压缩一次
5. -XX:CMSInitiatingOccupancyFraction: 当老年代使用达到该比例时会触发FullGC(默认
是92,这是百分比)
6. -XX:+UseCMSInitiatingOccupancyOnly:只使用设定的回收阈值(-
XX:CMSInitiatingOccupancyFraction设定的值),如果不指定,JVM仅在第一次使用设定
值,后续则会自动调整
7. -XX:+CMSScavengeBeforeRemark:在CMS GC前启动一次minor gc,目的在于减少
老年代对年轻代的引用,降低CMS GC的标记阶段时的开销,一般CMS的GC耗时 80%都在
remark阶段
-
2.5)G1垃圾收集器
是一款面向服务器的垃圾收集器,主要针对配置多颗处理器及大容量内存的机器,以极高的效率满足GC停顿时间要求的同时,还具备高吞吐量性能特征;
一般公司用不到,只会出现在大容量服务器的场景下才会使用;堆分配内存10G左右;
G1将堆划分为多个大小相等的独立区域(Region),JVM最多有2048个Region;
一般Region大小等于堆大小除以2048,例如:堆大小为4096M,则Region大小为2M,也可以使用参数:-XX:G1HeapRegionSize手动指定Region大小,但小白建议使用默认设置;
保留了年轻代和老年代的概念,但不再是物理隔阂,他们都是Region的集合,且可以不连续;
默认年轻代堆内存占比5%。例如:堆大小为4096M,年轻代占据200M左右,对应大概是100个Region;
可以通过-XX:G1NewSizePercent设置新生代初始占比,在系统实际运行中,JVM会不停的给年轻代增加更多的Region,但最多新生代的占比不会超过60%,可以通过-XX:G1MaxNewSizePercent进行调整。
年轻代中Eden与Survivor对应的Region也跟之前的一样,默认8:1:1;
一个Region可能之前是年轻代,如果进行了垃圾回收,之后可能又会变成老年代,也就是说Region的区域属性是会动态变化的;
G1对大对象的处理专门分配了Humongous区,超过一个Region大小的50%G1就认为是大对象;大对象并不直接进入老年代;
运作步骤:
1)初始标记:与CMS一样
2)并发标记:与CMS一样
3)最终标记:与CMS的重新标记一样;
4)筛选回收:这个是G1特别的地方,先对各个Region的回收价值和成本进行排序,根据用户所期望的GC停顿时间来进行处理的(默认是200MS),也可以使用-XX:MaxGCPauseMillis参数来指定回收计划;
G1使用的回收算法是复制算法,将一个Region中存活的对象复制到另外一个Region中不会像CMS那样出现很多碎片还需要整理一次,G1采用的复制算法回收几乎不会有太多的内存碎片;
G1特点总结:
1)并行与并发:充分利用CPU,在多核环境下的硬件优势,使用多个CPU来缩短业务停顿事件。其他收集器元宝需要停顿Java线程来执行GC动作,但G1收集器仍然可以通过并发的方式让程序继续执行;
2)分代收集:虽然可以不需要其他收集器配合就能独立管理整个GC堆,但还保留了分代的概念;
3)空间整合:与CMS的标记清理算法不同,G1从整体来看是基于标记整理,从局部来看是基于复制算法;
4)可预测的停顿:与CMS最大的差别也是优势,虽然降低停顿事件是G1与CMS共同的关注点,但G1除了追求停顿外,还能建立可预测停顿事件的模型,可以让使用者明确制定在一个时间段内完成垃圾收集
G1收集器参数设置:
-XX:+UseG1GC:使用G1收集器
-XX:ParallelGCThreads:指定GC工作的线程数量
-XX:G1HeapRegionSize:指定分区大小(1MB~32MB,且必须是2的幂),默认将整堆划分为
2048个分区
-XX:MaxGCPauseMillis:目标暂停时间(默认200ms)
-XX:G1NewSizePercent:新生代内存初始空间(默认整堆5%)
-XX:G1MaxNewSizePercent:新生代内存最大空间
-XX:TargetSurvivorRatio:Survivor区的填充容量(默认50%),Survivor区域里的一批对象(年龄
1+年龄2+年龄n的多个年龄对象)总和超过了Survivor区域的50%,此时就会把年龄n(含)以上的对
象都放入老年代
-XX:MaxTenuringThreshold:最大年龄阈值(默认15)
-XX:InitiatingHeapOccupancyPercent:老年代占用空间达到整堆内存阈值(默认45%),则执行
新生代和老年代的混合收集(MixedGC),比如我们之前说的堆默认有2048个region,如果有接近1000个region都是老年代的region,则可能就要触发MixedGC了
-XX:G1HeapWastePercent(默认5%): gc过程中空出来的region是否充足阈值,在混合回收的时候,对Region回收都是基于复制算法进行的,都是把要回收的Region里的存活对象放入其他
Region,然后这个Region中的垃圾对象全部清理掉,这样的话在回收过程就会不断空出来新的
Region,一旦空闲出来的Region数量达到了堆内存的5%,此时就会立即停止混合回收,意味着本次混合回收就结束了。
-XX:G1MixedGCLiveThresholdPercent(默认85%): region中的存活对象低于这个值时才会回收
该region,如果超过这个值,存活对象过多,回收的的意义不大。
-XX:G1MixedGCCountTarget:在一次回收过程中指定做几次筛选回收(默认8次),在最后一个筛选回收阶段可以回收一会,然后暂停回收,恢复系统运行,一会再开始回收,这样可以让系统不至于单次停顿时间过长。

浙公网安备 33010602011771号