JVM垃圾回收机制

引用计数法

判断一个对象是否是垃圾.在一个对象被引用时加一,被去除引用时减一

GC Root Tracing 算法

解决引用计数法存在的循环引用问题. 从 GC Root 出发,所有可达的对象都是存活的对象,而所有不可达的对象都是垃圾

GC Root 是一组活跃引用的集合

  • 所有当前被加载的 Java 类
  • Java 类的引用类型静态变量
  • Java类的运行时常量池里的引用类型常量
  • VM的一些静态数据结构里指向GC堆里的对象的引用
  • 等等

垃圾回收算法

垃圾回收算法简单地说有三种算法:标记清除算法、复制算法、标记压缩算法

标记清除算法

分为两个阶段:标记阶段和清除阶段.

  • 标记阶段,标记所有由 GC Root 触发的可达对象.所有未被标记的对象就是垃圾对象
  • 清除阶段,清除所有未被标记的对象

会产生内存碎片,但是不需要移动太多对象,比较适合在存活对象比较多的情况

复制算法

将原有的内存空间分为两块,每次只使用一块,在垃圾回收时,将正在使用的内存中的存活对象复制到未使用的内存块中。之后清除正在使用的内存块中的所有对象,之后交换两个内存块的角色,完成垃圾回收

需要将内存空间折半,并且需要移动存活对象. 但清理后不会有空间碎片,比较适合存活对象比较少的情况

标记压缩算法

标记压缩算法可以说是标记清除算法的优化版,其同样需要经历两个阶段,分别是:标记结算、压缩阶段。在标记阶段,从 GC Root 引用集合触发去标记所有对象。在压缩阶段,其则是将所有存活的对象压缩在内存的一边,之后清理边界外的所有空间

分代思想

单独采用任何一种垃圾回收算法,效果都不会很好. 因此在实际的垃圾回收算法中采用了分代算法

根据 JVM 内存的不同内存区域,采用不同的垃圾回收算法.

对于存活对象少的新生代区域,比较适合采用复制算法.这样只需要复制少量对象,便可完成垃圾回收,并且还不会有内存碎片

对于老年代这种存活对象多的区域,比较适合采用标记压缩算法或标记清除算法,这样不需要移动太多的内存对象

新生代内存比例分析

新生代内存分为Eden区,from区,to区三个区域. 比例为8:1:1

新生代对象特点是生存时间短,回收发生时是将Eden和Survivor中还存活的对象复制到另一个Survivor空间上. 按默认分配方式,新生代内存利用率为90%.如果仅分配两块内存提供给复制算法使用,利用率为50%.

文章链接 https://fangzongzhou.github.io/2020/11/11/计算机/技术栈/Java/JVM/JVM垃圾回收机制/