引用计数算法
- 对象每当被引用一次在其头部计数器加一,引用失效,头部减一,计数器为0时代表该对象没有任何引用,视为垃圾。
- 缺点:无法解决循环引用问题。
可达性分析(java使用)
- 通过GC Roots沿引用开始搜索,没有被扫描到的即视为垃圾。
- GC时常说的标记过程就是应用可达性分析算法进行标记;注,标记标记到的都是存活的对象。
java中的GC Roots
- 虚拟机栈中的引用的对象
- 常量池中的引用(jdk7及以前中的String对象全部分配在StringPool中,jdk8开始的StringPool可能是一个指向堆中String对象的引用)。
- 本地方法栈中使用的对象
- 虚拟机内部的引用,如基本数据类型的class对象,常驻的异常对象,系统类加载器等。
- 被synchronize持有的对象
- jvm内部信息的一些对象
- 分区收集时,其他区的引用。(如:G1中对一个Region收集时,其他Region的引用)
并发下的可达性分析
- gc与用户线程并发会产生的问题(如:a->b->c):
产生的问题
并发问题一
- c扫描结束
- c对象被gc标记为存活对象
- ==b->c被用户线程取消==(gc不知道)
- gc清理垃圾(c没有被清理掉,浮动垃圾)
并发问题二
- a扫描结束,b扫描中
- ==b->c被用户线程取消==(正在扫描b,gc知道),c被标记为垃圾
- ==a->c建立引用关系==(gc不知道)
- gc清理垃圾(c被清理)
解决方案
增量更新
==a到c建立引用关系==时,a会被标记为需要被重新扫描的状态,并发标记后,以a为根,重新扫描一次。不能处理并发问题一。
原始快照
==b到c断开引用关系==时,b会被标记为需要被重新扫描的状态,以b为根重新按照扫描前的快照重新扫描,当扫描到c时,借助OopMap记录能够判断c被引用,将c标记为存活对象。