垃圾标记阶段: 对象存活判断
- 在堆里存放着几乎所有的Java对象实例,在GC执行垃圾回收之前,首先
需要区分出内存中哪些是存活对象,哪些是已经死亡的对象。
只有被标记为已经死亡的对象,GC才会在执行垃圾回收时,释放掉其所占用的内存空间,因此这个过程我们可以称为垃圾标记阶段。 - 那么在JVM中究竟是如何标记一个死亡对象呢?简单来说,当一个对象已经不再被任何的存活对象继续引用时,就可以宣判为已经死亡。
- 判断对象存活一般有两种方式:
引用计数算法
和可达性分析算法
。
引用计数算法
- 引用计数算法(Reference Counting)比较简单,对每个对象保存一个整型的
引用计数器属性。用于记录对象被引用的情况。
- 对于一个对象A,只要有任何一个对象引用了A,则A的引用计数器就加1;当引用失效时,引用计数器就减1。只要对象A的引用计数器的值为0,即表示对象A不可能再被使用,可进行回收。
- 优点:
实现简单,垃圾对象便于辨识;判定效率高,回收没有延迟性。
- 缺点:
- 它需要单独的字段存储计数器,这样的做法增加了
存储空间的开销
。 - 每次复制都需要更新计数器,伴随着加法和减法操作,这增加了
时间开销
。 - 引用计数器有一个严重的问题,即
无法处理循环引用
的情况。这是一条致命缺陷,导致在Java的垃圾回收器中没有使用这类算法。
- 它需要单独的字段存储计数器,这样的做法增加了
小结
- 引用计数算法,是很多语言的资源回收选择,例如因人工智能而更加火热的Python,它更是同时支持引用计数和垃圾收集机制。
- 具体哪种最优是要看场景的,业界有大规模实践中仅保留引用计数机制,以提高吞吐量的尝试。
- Java并没有选择引用计数器,是因为其存在一个基本的难题,也就是很难处理循环引用关系。
- Python如何解决循环引用?
- 手动解除: 很好理解,就是在合适的时机,解除引用关系。
- 使用弱引用weakref,weakref是python提供的标准库,旨在解决循环引用。