垃圾算法类型
1. 标记-清除 算法
算法思想:
算法两个阶段:
1. 标记阶段:标记出所有需要回收的对象
2. 清除阶段:统一回收所有被标记的对象
标记阶段:(先进行可达性分析)
1. 第一次标记 & 筛选
对象在可达性分析后就会被第一次标记 & 筛选
a.不筛选 = 继续留在“即将回收”的集合里
b.筛选 = 从 “即将回收”的集合取出
c.筛选的标准:该对象是否有必要执行`finalize()`方法(有必要需人为设置,否则判断该对象死亡)
2. 第二次标记 & 筛选
该对象会被放到一个 F-Queue 队列中,并由 虚拟机自动建立、优先级低的Finalizer 线程去执行 队列中该对象的finalize()
finalize()只会被执行一次
但并不承诺等待finalize()运行结束。这是为了防止 finalize()执行缓慢 / 停止 使得 F-Queue队列其他对象永久等待。
在执行finalize()过程中,若对象依然没与引用链上的GC Roots 直接关联 或 间接关联(即关联上与GC Roots 关联的对象),那么该对象将被判断死亡,不筛选(留在”即将回收“集合里) 并 等待回收
优点:
- 算法简单 实现简单
缺点:
- 标记&删除效率低
- 用的同一块内存进行存储,当发生GC时,容易无连续的内存,供使用
适用场景:对象存活高 & GC几率低(如老年代区域)
2.复制算法
该算法的出现是为了解决 标记-清除算法中 效率 & 空间问题的。
算法思想:将内存分为了大小相等的两块,每次只使用其中一块, 当使用的这块内存用完,就将这块内存存活对象 复制到另一块“未使用”的内存上,最终将使用的那块内存清理掉。
缺点:内存被分成了两块,内存大小变成了一半,当对象存活率较高的情况需要做很多的复制操作。
3.标记-整理法
此类算法类似于 "标记-清除"。只是在中间多加了一步:整理内存
算法思路:
a.标记阶段:标记出所有需要回收的对象
b.整理阶段:让所有存活的对象向一端进行移动
c.清除阶段:统一清除端以外的对象
4.分代收集法
主流的虚拟机都使用这种算法
根据对象存活周期的不同,将Java堆内存,分为:新生代 & 老生代。
新生代:采用复制算法(这里面的存活率都不高,容易发生垃圾收集行为。Mionr GC)
老年代:标记-清除算法,标记-整理算法(Full GC || Major GC)
新生代内存分配比例:8:1:1
具体存储的过程:
1.新建的对象一般会优先分配到 Eden区,From Survivor区(大对象,如长的字符串和数组就会直接分配到老年代,避免发生大量的内存复制)
2.这些对象经过第一个Minor GC如果还存活,就会移动到 To Survivor区,一次清理掉Eden,From Survivior区
3.在To Survivior区每经历一轮Minor GC,该对象的年龄就加1
4.当对象的年龄达到一定时(阀值默认=15),就会移动到老年代,
注意:`From Survivor` 和 `To Survivor`之间会经常互换角色。
每次发生GC时,把Eden区和 From Survivor区中 存活且没超过年龄阈值的对象 复制到To Survivor区中(此时To Survivor变成了From Survivor),然后From Survivor清空(此时From Survivor变成了To Survivor)
优点:效率高,不同的区域采用不同的GC算法