1. 简介
在并发标记结束后,ZGC进入非强引用的并发标记和处理阶段。主要负责处理软引用、弱引用、虚引用、FinalReference(实现了Finalize方法的类的实例)。
2. 引用
2.1 引用的基本概念
引用的类型
memory/referenceType.hpp
enum ReferenceType {
REF_NONE, // 正常的类
REF_OTHER, // java/lang/ref/Reference的子类,但不在下面里面
REF_SOFT, // 软引用,java/lang/ref/SoftReference的子类
REF_WEAK, // 弱引用,java/lang/ref/WeakReference的子类
REF_FINAL, // java/lang/ref/FinalReference的子类
REF_PHANTOM // 虚引用,java/lang/ref/PhantomReference的子类
};
引用主要有4种状态:
- active:活跃
- pending:对象进入pending列表
- enqueued:对象进入引用队列
- Inactive:不活跃,可以回收
pending转变为enqueued由Java线程ReferenceHandler负责,其他由GC线程负责。
2.2 java.lang.ref.Reference
相关引用类别均继承了抽象类java.lang.ref.Reference,Reference主要包含如下成员变量:
// jvm在gc时会将要处理的对象放到这个静态字段上面。
private static Reference<Object> pending = null;
// 表示要处理的对象的下一个对象。即可以理解要处理的对象也是一个链表,通过discovered进行排队
// processPendingReferences只需要不停地拿到pending,然后再通过discovered不断地拿到下一个对象赋值给pending即可,直到取到了最有一个。
// 因为这个pending对象,两个线程都可能访问,因此需要加锁处理。
transient private Reference<T> discovered; /* used by VM */
// 引用中的对象,由GC决定何时、是否回收
private T referent; /* Treated specially by GC */
// 即描述当前引用节点所存储的下一个即将被处理的节点。但next仅在放到queue中才会有意义
Reference next;
// 引用的队列,tryHandlePending最后一步就是把Reference对象入队。new的时候如果是null就不入队了。
volatile ReferenceQueue<? super T> queue;
2.3 ReferenceHandler线程
Reference的static代码块中会启动一个线程,该线程会死循环调用processPendingReferences方法,方法
private static class ReferenceHandler extends Thread {
private static void ensureClassInitialized(Class<?> clazz) {
try {
Class.forName(clazz.getName(), true, clazz.getClassLoader());
} catch (ClassNotFoundException e) {
throw (Error) new NoClassDefFoundError(e.getMessage()).initCause(e);
}
}
static {
ensureClassInitialized(<