2.1 引用计数
什么是引用计数呢?打个比方A a = new A()
,代码中 A 对象被引用 a 所持有,此时引用计数就会 +1 ,如果 a 将引用置为 null 即a = null
此时对象 A 的引用计数就会变为 0 ,GC算法检测到 A 对象引用计数为 0 就会将其回收。很简单,但引用计数存在一定弊端
场景如下:
A a = new A();
B b = new B();
a.next = b;
b.next = a;
a = null;
b = null;
执行完上述代码后 A 和 B 对象会被回收吗?看似引用都已经置为 null ,但实际上 a 和 b 的 next 分别持有对方引用,形成了一种相互持有引用的局面,导致A 和 B 即使成了垃圾对象且不能被回收。有些同学可能会说,内存泄漏太容易看出来了, a 和 b 置空前将各自的 next 置为空不就完了。嗯,这样说没错,但是在实际业务中面对庞大的业务逻辑内存泄漏是很难一眼看出的。所以JVM在后来摒弃了引用计数,采用了可达性分析。
2.2 可达性分析
可达性分析其实是数学中的一个概念,在JVM中,会将一些特殊的引用作为 GcRoot ,如果通过 GcRoot 可以访达的对象不会被当作垃圾对象。换种方式说就是,一个对象被 GcRoot 直接 或 间接持有,那么该对象就不会被当作垃圾对象。用一张图表示大概就是这个样子:
图中A、B、C、D可
以被 GcRoot 访达,所以不会被回收。E、F
不能被 GcRoo