如何判断一个对象死亡?

当一个对象已经不再被任何的存活对象继续引用时(即没人用),就可以宣判为已经死亡。
判断对象存活的算法一般有两种:引用计数算法和可达性分析算法

请问什么是引用计数算法

引用计数算反(Reference Counting)比较简单,对每个对象保存一个整型的引用计数属性,用于记录对象被引用的情况。
对于一个对象A,只要有任何一个对象引用了A,则A的引用计数器就加1;当引用失效时,引用计数器就减1.
只要对象A的引用计数器的值为0,即表示对象A不可能再被使用,可进行回收。

该算法的优缺点:

优点:实现简单,垃圾对象便于辨识;判定效率高,回收没有延迟性。
缺点:需要单独的字段存储计数器,这样的做法增加了存储空间的开销。
每次赋值都需要更新计数器,伴随着加法和减法操作,增加了时间的开销。
引用计数器有一个严重的问题,即无法处理循环引用的情况。这是一条致命缺陷,导致Java的垃圾回收器中没有使用这类算法。
image.png

  1. 创建对象a,存储在堆中,main方法的栈帧中的局部变量a引用了堆空间Test01实例a地址。
  2. 创建对象b,存储在堆中,main方法的栈帧中的局部变量b引用了堆空间Test01实例b地址。
  3. Test01实例a的obj引用了Test01的实例b地址
  4. Test01实例b的obj引用了Test01的实例a地址

当执行a=null; b = null;时,就变成如下图,将会导致堆循环相互引用,从而导致gc回收失败。
image.png

Java是否用了计数算法?

  1. /**
  2. -Xms30M
  3. -Xmx30M
  4. -XX:+PrintGCDateStamps
  5. -XX:+PrintGCDetails
  6. -XX:+PrintHeapAtGC
  7. */
  8. public class Test01 {
  9. private Test01 obj=null;
  10. byte[] bytes = new byte[2*1024*1024];
  11. public static void main(String[] args) {
  12. //一:直接引用
  13. //a引用实例a,所以实例a引用数为1
  14. Test01 a=new Test01();
  15. //b引用实例b,所以实例b引用数为1
  16. Test01 b=new Test01();
  17. //二:相互引用
  18. //a.obj引用了实例b,故实例b引用数+1=2
  19. a.obj=b;
  20. //b.obj引用了实例a,故实例a引用数+1=2
  21. b.obj=a;
  22. //三:删除引用
  23. //删除a引用实例a,故实例a引用数-1=1
  24. a=null;
  25. //删除b引用实例b,故实例b引用数-1=1
  26. b=null;
  27. //四:垃圾清除,如果采用引用算法的话,会导致内存无法释放。
  28. System.gc();
  29. }
  30. }