一、概述
本篇博客是基于《深入理解Java虚拟机》一书的读书笔记,主要记录的是关于 GC 方面的相关知识,脉络如下:
- 什么是引用
- 引用的四种基本类型
- 判断对象已死
- 垃圾收集算法
- HotSpot 的算法实现
- 对象内存分配与回收策略
- 思维导图
二、什么是引用
引用可用于判断对象是否存活,所以想要了解 GC,那么对于引用的了解必不可少,要知道什么是对象,我们还得先了解一下什么是对象?
我们都知道,在 Java 中万物皆对象,每个对象都是某个类(Class)的一个实例(Instance),例如人类是一个类,而具体到人类当中的每个人,例如张三,就是这个类的一个实例了。在了解了什么是对象之后,我们接下来看看什么是引用?
在《Java编程思想》中有这么一段话:
每种编程语言都有自己的数据处理方式。有些时候,程序员必须注意将要处理的数据是什么类型。你是直接操纵元素,还是用某种基于特殊语法的间接表示(例如C/C++里的指针)来操作对象。所有这些在 Java 里都得到了简化,一切都被视为对象。因此,我们可采用一种统一的语法。尽管将一切都“看作”对象,但操纵的标识符实际是指向一个对象的“引用”(reference)。
举一个例子:
Person person = new Person("张三");
这行代码中,person
指的是一个引用(具体来说是强引用,后面会介绍到),那么对象在哪里呢?对象其实指的就是 new Person("张三")
这一部分。这个过程我们可以理解为,Java 在堆区中创建了一个 Person
对象(张三),然后将 person
指向了该对象,示意图如下所示:
三、引用的四种基本类型
在知道了何为引用之后,接下来介绍引用的基本类型,它可分为以下 4 种类型:
1. 强引用(Strong Reference)
- 在程序代码中普遍存在,形如
Object o = new Object()
这类的引用即为强引用。 - 只要强引用还存在,垃圾回收器永远都不会去回收掉被引用的对象。
- 从上面第 2 点可以得知,当出现内存不足的情况时,JVM 宁愿抛出 OOM 也不愿意回收强引用对象。
2. 软引用(Soft Reference)
- 用于描述一些有用但非必须的对象。
- 使用方式:
SoftReference<String> sr = new SoftReference<String>(str);
- 只具有软应用的对象会在内存空间不足的时候进行 GC,如果在 GC 过后内存空间仍然不足才会抛出内存溢出异常。
- 可用于实现内存敏感的高速缓存。
3. 弱引用(Weak Reference)
- 弱引用和软引用一样用于描述有用但非必须的对象,但它的强度比软引用还弱。
- 在 GC 的时候只具有弱引用的对象必定会被回收掉。
- 使用方式:
WeakReference<String> sr = new WeakReference<String>(str);
- 适用于引用偶尔被使用且不影响垃圾收集的对象。
4. 虚引用(Phantom Reference)
- 最弱的一种引用关系,不会决定对象的生命周期。
- 任何时候都可能被垃圾回收器回收。
- 跟踪对象被垃圾回收器回收的活动,起哨兵作用。
- 必须和引用队列
ReferenceQueue
联合使用,其中ReferenceQueue
是用于存储被回收的对象。
这 4 种引用类型的强弱关系即为 强引用 > 软引用 > 弱引用 > 虚引用
四、判断对象已死
对于垃圾回收机制,我们需要明晰两个问题:
- 垃圾回收机制回收的是什么样的对象?
- 该对象如何被判定为垃圾?
第一个问题很简单,垃圾回收机制回收的就是堆区上的垃圾对象。
第二个问题,如何判定对象已死,就需要介绍接下来的两种算法:引用计数算法和可达性算法。
1. 引用计数算法
该算法的思想是:给对象添加一个引用计数器,每当有一个地方引用它时,计数器值就加 1,当引用失效时,计数器值减 1。任何时刻计数器为 0 的对象就是不可能再被使用的了,也就是说此时对象为垃圾对象。
引用技术算法的优点是实现简单,效率很高,但是它的缺点却也非常明显,非常难以解决对象之间循环引用的问题,如下例子所示:
public class