对象已死?

2020-09-01  本文已影响0人  风暴预言家

  前言:在堆里面存放着Java世界中几乎所有的对象实例,垃圾收集器在对堆进行回收前,第一件事情就是要确定这些对象之中哪些还"存活",哪些已经"死去"。

1.引用计数法

  在对象中添加一个引用计数器,每当一个地方引用它时,计数器值就加一;当引用失效时,计数器值就减一;任何时刻计数器为零的对象就是不可能再被使用的对象。

  但是在Java领域,至少主流的Java虚拟机中没有选用引用计数器算法来管理内存,主要原因是,这个看似简单的算法有很多例外情况需要考虑,必须要配合大量额外处理才能保证正确地工作,比如单纯的引用计数就很难解决对象之间相互循环引用。

2.可达性分析算法

  当前主流的商用程序语言的内存管理子系统,都是通过可达性分析算法来判定对象是否存活。这个算法的基本思路就是通过一系列称为"GC Roots"的根对象作为起始节点集,从这些节点开始,根据引用关系向下搜索,搜索过程所走过的路径称为"引用连"(Reference Chain)。

在Java技术体系内,固定可作为GCRoots的对象包括以下几种:

  1. 在虚拟机栈(栈中的本地变量表)中引用的对象,譬如各个线程被调用的方法堆栈中使用到的参数、局部变量、临时变量等。
  2. 在方法区中类静态属性引用的对象,譬如Java类的引用类型静态变量。
  3. 在方法区中常量引用的对象,譬如字符串常量池里的引用。
  4. 在本地方法栈中JNI引用的对象。
  5. Java虚拟机内部的引用,如基本数据类型对应的Class对象,一些常驻的异常对象(比如NullPointExecption)等,还有系统类加载器。
  6. 所有被同步锁持有的对象。
  7. 反映Java虚拟机内部情况的JMXBean、JVMTI中注册的回调、本地代码缓存等。
  8. 如果使用局部收集,还可能增加其他区域临时加入对象。

再谈引用

  无论是引用计数法还是可达性分析法都和引用离不开关系,在JDK1.2之前,Java里面的引用是很传统的引用定义:如果reference类型的数据中存储的数值代表的是另外一块的起始地址,就称改reference数据是代表某块内存、某个对象的引用。这种定义并没有什么不对,只是有些过于狭隘了。一个对象在这种定义下只有"被引用"或者"未被引用"两种状态,对于描述一些"食之无味,弃之可惜"的对象就显得无能为力。譬如缓存功能,当内存空间足够时,能保留在内存之中,如果内存空间在进行垃圾收集后仍然紧张,那就可以抛弃这些对象。

  在JDK1.2之后,Java增加了强引用,软引用,弱引用,虚引用。

  1. 强引用(Strongly Reference):
Object obj = new Object();
  1. 软引用(Soft Reference): 在系统将要发生内存溢出的前,会把这些对象列进回收范围之中进行第二次回收。
  2. 弱引用(Weak Reference): 在下一次垃圾回收机进行收集的时候进行回收。
  3. 虚引用(Phantom Reference): 没有任何实际意义,对对象的生命周期没有印象,只在垃圾回收的时候进行系统通知。
上一篇下一篇

猜你喜欢

热点阅读