JVM垃圾回收
分代回收理论:
1.大多数对象都是"朝生夕死" --新生代
2.经历过多次GC而没被回收的对象越难以回收 --老年代
复制算法 copying
1.实现简单
2.无内存碎片
3.利用率为50%
4.需要调整指针
Eden区的来源
1.基于appel式回收,Eden与s1,s0的比值8:1:1,利用率从50%提升到90%
2.提高空间利用率,空间分配担保(由老年代来兜底)
标记-清除算法 Mark-Sweep
1.位置不连续,会产生碎片
2.效率比较低
3.需要扫描两次,需要整理碎片
4.对比复制算法,空间利用率100%
标记-整理算法 Mark-Compact
1.没有内存碎片
2.效率最低
3.两边扫描, 需要调整指针,此时线程要暂停以更新引用指针
4.利用率100%
基于JDK1.8,常用的垃圾回收器, 垃圾回收器是执行回收算法的执行者
1.Serial/Serial Old 最古老的单线程的回收器, stop the world(STW)
-XX:+UseSerialGC
2.Parallel Scavenge(ParallerGC) / Parallel Old /ParNew(专门回收新生代)多线程并行回收器 (1.8默认的)
-XX:+UseParallelGC
-XX:+UseParallelOldGC
-XX:+MaxGCPauseMillis=500 设置垃圾回收暂停最大时间,JVM尽量向此值靠近,非精确值,慎用
-XX:+UseAdaptiveSizePolicy 启用自适应分代大小,无需手动设置各代大小, JDK1.8默认
3.G1, CMS(专门回收老年代,与ParNew配对) 并发垃圾回收器, 让用户线程与垃圾回收线程并行跑一段时间, 即可减少STW时间
(1,初始标记... 2.重新标记(STW)... 3.并发清理垃圾)
- 新生代回收器中,都使用了复制算法
- 老年代回收器中,只有CMS使用了标记清除算法, 其他都使用了标记整理算法
CMS并发回收图示
CMS中的问题
1.CPU敏感, 会占用CPU资源,如果CPU核数少,可能会造成卡顿
2.浮动垃圾, 即并发清理垃圾过程中,用户线程依然在产生垃圾, 只能等到下一次GC再处理,所以触发垃圾回收的时机要提前一些,以给浮动垃圾预留空间,如果预留空间不够,
则会切换成SerialOld回收器执行
3.内存碎片
4.所以需要经常重启应用.......!!!! 所以后续出现了G1
Garbage First (G1) 回收器
-XX:+UseG1GC 建议在大堆(6g以上)使用G1
-XX:+MaxGCPauseMillis=500 G1可以满足此设置
-XX:
1.STW可预测,可控制,追求尽量少的停顿时间
2.内存区域重新划分,区分传统分代
图说明:把大分代切分成小区域,思想不变, 新增的Humongous用于装大对象,实际属于old区,根据大对象size来决定占用几个H区
3.实现可预测的停顿,Region区域筛选停顿
4.也是使用复制-标记整理算法
5.无内存碎片
G1运行过程中:
1.TAMS(Top at Mark Start) 算法
并发标记过程中新增的对象不划入垃圾数据
2.SATB(Snapshot-at-the-begin) 算法
解决并发标记过程中,漏标记问题
G1执行过程示意
各种垃圾回收器整理