- 垃圾标记算法
- 垃圾回收算法
- major gc、mini gc、full gc、mixed gc 又是什么,怎么触发的
- 垃圾回收器的介绍
- Safe Point 和 Safe Region
- 什么是 TLAB 和 PLAB ?
- CMS、G1 新生代的 GC 如何避免全堆扫描
- CMS 和 G1 为了防止并发时的漏标分别用了什么手段
- 什么是 logging write barrier
- CMS 常见问题
- GC 事件和日志分析
- JVM 常用参数汇总
关注公众号,一起交流:潜行前行
1 垃圾标记算法
引用计算法
- 引用计数法是最简单有效的垃圾标记方法,它会把对象被引用的次数记录下来,当被引用时,计数加一。当其他变量不再指向目标对象时,则引用减一。对象引用数为零时 ,则可以进行内存回收释放
- 无法解决循环引用问题
根可达性分析
- 从 GC Root 开始进行对象搜索,可以被搜索到的对象即为可达对象,不可达对象便可以作为垃圾被回收掉。目前 Java 中主流的虚拟机均采用此算法
- 在Java语言里,可作为GC Roots的对象包括下面几种:
- 虚拟机栈(栈帧中的本地变量表)中的引用的对象
- 方法区中的类静态属性引用的对象
- 方法区中的常量引用的对象
- 本地方法栈中JNI(即一般说的Native方法)的引用的对象
2 垃圾回收算法
- 复制 :将一块内存区域进行对半分,当一半的内存使用完时,便将其中存活的对象复制到另一半内存区域中,原先的区域进行回收。不存在内存碎片问题,实现简单运行高效,但是有个缺点,就是对内存的利用率只有 50%
- 标记清除 :算法分为 “ 标记 ” 和 “ 清理 ”两个阶段
- 标记阶段 :标记出所有需要回收的对象
- 清除阶段 :标记完成后,统一清除回收被标记的对象
- 由于对象之前在内存中的分布是无规律的,标记清除算法会产生大量不连续的内存碎片,造成连续的大内存空间缺失,阻碍大内存对象的分配,严重时会触发垃圾回收,甚至出现 OutOfMemeryError。而且如果大部分的对象是朝生夕死的,标记的对象就会更多,效率更低
- 标记整理 :步骤与 标记清除步 骤一致,但它的第二步是整理标记之外的所有对象,将所有对象向前移动,之后直接回收掉存活对象之外的内存区域。标记整理 不会存在内存碎片,但是效率是偏低的
按年代划分-分代算法
- 新生代回收 (Minor GC/Young GC):指只是进行新生代的回收
- 老年代回收 (Major GC/Old GC):指只是进行老年代的回收。目前只有 CMS 垃圾回收器会有这个单独的回收老年代的行为
- 整堆回收 (Full GC):收集整个堆,包括年轻代、老年代,如果有永久代的话还包括永久代
3 major gc、mini gc、mixed gc又是什么,怎么触发的?
- major gc :个人理解应该是指 old gc。不过有些人认为和 full gc 等价
- 执行 System.gc()、jmap -dump 等命令会触发 full gc
- 有永久代的话,永久代满了也会触发 full gc
- 大对象直接在老年代申请分配,如果此时老年代空间不足则会触发 full gc
- 新生代对象 gc 年龄到达阈值需要晋升,老年代如果放不下的话会触发 full gc
- mini gc :指的也是年轻代的 young gc
- 年轻代的 eden 快要被占满的时候会触发 young gc
- eden 快满的触发因素有两个,一个是为对象分配内存不够,一个是为 TLAB 分配内存不够
- mixed gc :这个是 G1 收集器特有的,指的是收集整个年轻代和部分老年代的 GC
- 在 young gc 之后,当老年代的堆占有率达到参数 (-XX:InitiatingHeapOccupancyPercent) 设定的值时则触发 mixed GC
4 垃圾回收器的介绍
Serial New 和 Serial Old
Stop The World
Parallel Scavenge 和 Parallel Old
- 为了提高 jvm 的回收效率,jvm 使用了多线程的垃圾回收器,关注吞吐量的垃圾回收器,可以更高效的利用CPU 时间,从而尽快完成程序的运算任务
- Parallel Scavenge 收集器提供了两个参数用于精确控制吞吐量,可以分别是控制最大垃圾收集停顿时间
- -XX:MaxGCPauseMillis参数以及直接设置吞吐量大小的
- -XX:GCTimeRatio参数。其也经常被称为“吞吐量优先”收集器
ParNew 和 CMS
标记-清除
CMS 的回收流程
- 初始标记 :只标记与 GC Root 有直接关联的对象,这类的对象比较少,标记快。 需要 STW
- 并发标记 :并发标记与初始化标记的对象有关联的所有对象,这类的对象比较多所以采用的并发,与用户线程一起跑
- 并发预清理(Concurrent Preclean) :并发标记阶段是与应用线程并发执行的,有些引用关系已经发生改变,通过卡片标记(Card Marking),如果引用关系发生改变,JVM会将发生改变的区域标记位“脏区”(Dirty Card),然后在本阶段,这些脏区会被找出来,刷新引用关系,清除“脏区”标记
- 并发可取消的预清理(Concurrent Abortable Preclean) :和并发预清理阶段工作差不多,用来减少Final Remark 阶段的暂停时间。该阶段会不断循环处理:标记老年代的可达对象、扫描处理Dirty Card区域中的对象引用关系。循环中断条件
- 达到循环次数
- 达到