JVM - 分代回收

135 阅读3分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第6天,点击查看活动详情

STW是什么

image.png

GC的同时暂停一切用户线程(Stop the world)STW

如何杜绝STW带来的卡顿

  • 尽量减缓触发GC的次数
  • 尽量缩小GC的范围
  • 想办法让GC并行和并发

评价GC的一些指标

  • 吞吐量:回收范围(堆)大小/GC总耗时
  • 最大停顿耗时:最长的STW时间
  • 回收频率:垃圾回收的间隔时间的频率,频率越低越好
  • 响应时间:从一个实例变成垃圾到他被释放的时间
  • 空间利用率:堆中真正能够存储实例的空间占比

垃圾回收策略

分代回收

image.png

默认情况下的内存分配

  • 老年代栈堆堆2/3,轻代占1/3
  • 新生区占年轻代的4/5
  • 两个幸存区各占年轻代的1/10

分代年龄:对象每经历一次GC,而没有被回收分代年龄会+1

如果新生区空间不足,触发针对整个年轻代的young GC,将新生区的实例放到幸存区同时分代年龄会+1,如果一段时间后,新生又满类,则又回触发young gc,将新生代和幸存区的实例移动到另一个幸存区中,同时分代年龄+1,两个幸存区来回切换,分代年龄会不断增加。

  • 如果幸存区相同年龄的对象大小总和大大于幸存区的一半时,这些对象将进入老年代。
  • 如果幸存区中对象的分代年龄大于15也会进入老年代。
  • 如果是一个比较大的对象会直接放入老年代。

如果老年代也满类,则会触发full GC

GC的种类
  • Partial GC:只回收堆的一部分的GC
    • Young GC:只回收堆中年轻代的GC(Minor GC)
    • Old GC:只回收堆中老年代的GC(Major GC)
  • Full GC:回收整个堆的GC(major GC(主要))
分代回收本质

分代回收本质是一种基于经验得出的垃圾回收优化策略。

这些经验包括

  • 绝大多少的实例,生命周期都很短
  • 熬过越多次垃圾回收过程的实例,🈷越难以消亡
  • 跨代引用相对于同代引用来说仅占极少数
新生区
  • 新实例被创建后,优先分配到新生区,如果是大对象则直接进入老年代,避免反复移动大对象降低效率,避免啦大对象导致频繁young GC
  • 新生区不应碎片化严重,所以每次young gc都会清空新生区,避免碎片化,同时也能让下次GC的到来尽可能晚一些
幸存区
  • 幸存区是两个等大的区域轮流存放实例,确保每次GC都是把幸存区的实例放到to区(S0/S1),然后清空新生区+from(S1/S0),降低啦算法难度,还能避免内存碎片
  • 会导致年轻代浪费一个to区的空间,所以幸存区的大小通常不大,只是作为中间交换区域
老年代
  • 能够流转到老年代的实例,通常都是长生命周期的实例,或者大对象
  • 老年代空间最大,触发GC的频率最慢,所以适合存储长生命周期的实例,或者大对象

分代回收的优点

  • 能够筛选出生命周期不同的实例,让他们在不同时机被回收,避免每次都针对整个堆进行回收
  • 让不同的代,可以选择适合自己的不同的垃圾回收算法。