JVM垃圾收集

在这里插入图片描述

垃圾对象

引用计数法:
概念:在对象中添加一个计数器,当这个对象被引用时计数器加1,引用失效时时,计数器减1,任何计数器为0的对象都可被视为垃圾对象。
优点:实现简单,效率高。
缺点:无法解决循环引用的问题。循环引用即两个或多个对象之间循环调用,除此之外再无其他的引用,这些对象虽然为垃圾,计数器却无法为0导致不能被回收。因此这个方法目前没有垃圾收集器在使用。
可达性分析算法:
概念:
1.算法:从GC Roots根节点开始向下扫描,依次扫描结束后不能扫描到的对象视为垃圾对象
2.GCRoots:方法栈中的本地变量、静态变量、本地方法栈中的变量
3.引用:java中常见的引用有强引用、软引用、弱引用与虚引用。后两种在垃圾收集时一定会被回收,一般不使用。
PS:finalized()方法
当对象被标记为垃圾对象时,并不会立即被回收,jvm会判断该对象是否被finalized覆盖,如果没有,直接被回收,如果有则先执行finalized方法,若对象在该方法中实现自救,即与GC Roots或引用链上的对象产生关联,即可被移除“即将回收”列表。
一个对象的finalized方法只可被执行一次!

垃圾收集理论

分代收集理论
目前的垃圾收集器都是基于分代收集理论,即根据对象存活周期将堆空间分为新生代和老年代,然后根据对象的存活特点,选择合适的垃圾收集算法。

垃圾收集算法

标记-复制算法
概念:将内存空间平均分为两份,当一半的内存使用完毕后,就将存活对象全部移到另一半内存中,然后把这块内存整个清理掉。
特点:空间使用率不高,适合容易产生大量垃圾对象的新生代
标记-清除算法
概念:分为“标记”和“清除”两个步骤,触发GC时标记存活对象(或反过来标记垃圾对象,一般采用前者),然后将未标记对象全部清理掉。
特点:
1.效率低:当存活对象太多时,标记任务量会很大
2.空间利用率低:垃圾对象清理后会造成很多不连续的空间,容易发生内存足够却无法使用的现象
标记-整理算法
概念:同标记-清除算法一样,会先标记存活对象,然后将所有存活对象向一端移动,最后清理掉边缘区域的垃圾对象。
特点:清理后会留下连续的可用空间,解决了标记-清除算法在空见利用率低的问题,适合老年代。

垃圾收集器

Serial/SerialOld
概念:Serial单线程收集器,单线程收集垃圾,以及收集垃圾时需要停止当前所有线程(STW,stop the world)。SerialOld是Serial的老年代版本,主要用于jdk5及以前配合Parallel Scavenge使用和作为CMS的备用收集器。新生代使用标记-复制算法,老年代使用标记-整理算法
优点:简单高效,是单线程环境下垃圾收集的最好选择
缺点:由于收集过程中的STW,导致用户体验不佳
Parallel Scavenge/ParallelOld
概念:Serial的多线程版本,并发线程默认和CPU一致。除了单多线程之外,与Serial收集器其他行为类似。ParallelOld是parallel的老年代版本
优点:适合多线程下的垃圾收集,专注于系统吞吐量,即尽力使用更少的时间完成垃圾收集(jdk1.8的默认收集器)
缺点:由于收集过程中的STW,导致用户体验不佳
ParNew
概念:parallel的改进版本,主要为了能够配合CMS使用
特点:除了serial之外唯一能够配合cms使用的多线程收集器,真正意义上的并发收集器

CMS(Concurrent Mark Sweep)

概念:使用标记-清除算法实现并发收集老年代垃圾,几乎实现了用户线程与垃圾收集同时进行
过程
1.初始标记:stw,标记堆中的GC roots直接能引用的对象,此过程耗时极短
2.并发标记:用户线程启动,同时从GCroots遍历标记所有引用对象
3.重新标记:stw,此过程时长大于初始标记,但远远小于并发标记,只需根据增量更新更新对发生变化的对象重新标记,对于创建的对象一律标为黑色对象
4.并发清理:用户县城启动,同时进行垃圾清除工作
5.并发重置:重置对象的标记
优点:专注于提高用户体验,并发收集,低停顿。
缺点
1.与服务抢占CPU资源
2.由于并发标记,标记后的对象有可能发生变化,会产生浮动垃圾或漏标非垃圾对象
3.空间利用率低,由于使用标记-清除算法导致fullGC后会产生大量空间碎片,可通过-XX:+UseCMSCompactAtFullCollection参数设置清除后进行空间整理
4.可能在垃圾收集结束前再次触发fullGC,由于用户线程仍在运行,此时如果老年代空间不够用再次触发fullGC,即“concurrent mode failure”,此时cms会STW,使用serialOld完成垃圾收集工作。
底层算法实现:三色标记法
概念:从GCRoots出发,将扫描到的对象标记为三种颜色
①.黑色:该节点的所有引用存在且已经被扫描完毕
②.灰色:该节点存在引用,但目前至少有一个引用没有被扫描到
③.白色:没有扫描到的节点
被扫描前所有节点都为白色,由于用户线程与遍历扫描同时进行,对象状态发生变化可能造成多标和漏标的问题,多标产生的浮动垃圾可以在下一次进行垃圾收集时清理,而漏标属于严重的bug,cms主要通过写屏障和增量更新解决漏标问题
问题解决方案
漏标问题:
1.增量更新:在黑色对象产生新的引用时,将黑色对象标记为灰色对象,在重新标记阶段重新遍历扫描该对象的引用
2.原始快照(SATB):在对象删除引用时,将该引用记录下来,在重新标记阶段将该引用指向的对象标记为黑色,该对象有可能浮动垃圾,等待下一次GC时回收
实现方式:
1.写屏障:在对象引用发生变化的前后,对值进行更新操作(可以参照AOP)
2.读屏障:在对象引用发生变化前后,对引用进行记录操作
隔代引用问题:
记忆集:在新生代的内存中开辟一小块空间存储引用老年代的地址,GC时通过这一块记录的索引即可解决跨代引用的问题
卡表:记忆集的实现之一,将老年代已使用的内存空间分为一个个卡页,如果卡页中包含被新生代引用的数据,则将卡页符号位置为1,表示脏数据,新生代的卡表中存储这些卡页的索引地址,扫描时只需通过索引扫描被置为含有脏数据的卡页即可。

G1

概念
1.取消了分代的物理隔离,将整个堆内存分为大小相等的region区,JVM最多有2048个,比如堆大小为4096M时一个region区2M左右,是一个面向服务器,即以极高概率满足gc停顿时间并有具备高吞吐量的性能特征的垃圾收集器。
“-XX:G1HeapRegionSize”:手动指定region区的大小,建议默认。
2.分代概念:
①E:伊甸园区
②S:存活区
③O:老年代
④H:大对象区
新生代区域默认占整个堆内存的5%(可以设置),最大不超过60%(可以设置),eden与survivor区的比例默认依然为8:1:1(可以设置)。新生代与老年代的分配基本一样,不同的是大对象被分配了专属的humongous区,大对象是指超过region50%以上的对象(在这里大于1M的都属于大对象,可以根据具体应用场景设置);G1操作的单元为region,新生代和老年代的位置并不固定,而是依数据的存储位置而定
“-XX:G1NewSizePercent”:设置新生代初始占比
“-XX:G1MaxNewSizePercent”:设置新生代最大占比
GC分类
①YoungGC:当eden区存满5%时,不会立马触发moniorgc,G1会先计算eden区垃圾收集的时间是否接近用户指定的垃圾收集时间,如果远远小于,则继续往eden区存值,直到达到时间长度时才会触发一次YoungGC。
②MixedGC:堆内存使用达到指定(“-XX:InitiatingHeapOccupancyPercent”)值时触发MixedGC,清理新生代,一部分老年代(根据用户指定停顿时间)和大对象区中的垃圾对象,使用复制算法,将存活的对象复制到空的region中,当没有足够的region可以使用时,触发一次fullGc。
③FullGC:STW,采用单线程标记,清理,整理,耗时较长,以空出一部分region供下次MixedGC使用,Shenandoah优化为多线程了。
收集流程
初始标记:同cms的初始标记
并发标记:同cms的并发标记
最终标记:同cms的重新标记
筛选回收:stw,由用户指定垃圾收集时间(通过参数“-XX:MaxGCPauseMillis”),后台维护了一个优先列表,根据特殊算法在指定时间范围内优先多线程收集价值高的内存区域(耗时短,回收空间大),剩下的由下一次gc时回收
特点
并发与并行
分代收集
空间整合
可预测的停顿
漏标问题处理
相对于cms的写屏障+增量更新,G1使用写屏障+SATB(原始快照)的方式,这种方式与增量更新相比会产生更多的浮动垃圾,但对于G1来说,分批次处理垃圾数据是正常操作,所以也不存在浮动垃圾一说,同时由于G1的分区管理,会导致大概率的跨代引用问题,对此增量更新的节点扫描不如SATB效率高,因此G1的漏标问题使用了写屏障+SATB
JVM调优建议
主要注意“-XX:MaxGCPauseMillis”的设置,值太小,容易使GC的回收速度达不到空间的使用速度反而频繁发生单线程的FullGC从而更加影响用户体验;值太大可能导致程序运行很久很久才产生一次YoungGC导致存活对象过多,触发动态年龄分配或老年代担保机制,增加进入老年代的对象和触发频繁的FullGC。这个值默认是200ms,在内存足够大的时候可以将该值设置的小一点,可以使内存边回收边使用。

PS:如何选择垃圾收集器?
1.jdk1.8默认适用Parallel/ParallelOld
2.堆内存4G以下建议使用parallel,4-8建议使用ParNew+CMS,8G以上可以使用G1

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值