我的原则:先会用再说,内部慢慢来。
学以致用,根据场景学源码
文章目录
- 一、前言
- 二、架构
- 2.1 代码架构
- 2.2 UML流程图
- 三、思考 Finalizer Vs Cleaner 放一起
- 3.1 代码 demo
- 3.2 为什么 finalize 总是比 Cleaner 先执行 ?
- 四、Finalizer 源码剖析
- 4.1 父类 FinalReference
- 4.2 Finalizer 类
- 4.3 Finalizer 类变量
- 4.3.1 私有static变量 queue
- 4.3.2 私有static变量 unfinalized
- 4.3.3 next + prev 指针
- 4.3.3 私有 static final 变量 lock
- 4.4 对象初始化
- 4.4.1 构造方法
- 4.4.2 真正初始化对象的 register 方法
- 4.5 add 方法
- 4.6 remove 方法
- 4.7 hasBeenFinalized 方法
- 4.8 static块
- 4.9 内部类 FinalizerThread
- 4.9.1 VM.isBooted() 方法
- 4.9.2 SharedSecrets.getJavaLangAccess();
- 4.9.3 死循环执行 runFinalizer
- 4.9.3.1 注意一下 try-catch 吃掉异常
- 4.10 runFinalizer 方法
- 4.11 clear() 方法
- 4.12 总结一下
- 五、JVM负责调用的三方法
- 5.1 Register方法
- 5.2 runFinalization 方法
- 5.2.1 Runtime#runFinalization 方法
- 5.2.2 Finalizer.runFinalization 方法
- 5.2.3 forkSecondaryFinalizer 方法
- 5.3 runAllFinalizers 方法
- 5.3.1 Shutdown#runAllFinalizers 方法
- 5.3.2 Finalizer.runAllFinalizers 方法
- 5.4 总结一下
- 5.4.1 runAllFinalizers 与 runFinalization 的不同
- 六、番外篇
建议提前阅读:
=== 点击查看top目录 ===
public class _05_03_TestCleanerWithFinalize {
public static void main(String[] args) throws Exception {
int index = 0;
while (true) {
Thread.sleep(1000);
// 提醒 GC 去进行垃圾收集了
System.gc();
// 该对象不断重新指向其他地方,那么原先指针指向的对象的就属于需要回收的数据
DemoObject obj = new DemoObject("demo" + index++);
Cleaner.create(obj, new CleanerTask("thread_" + index++));
}
}
@Data
@AllArgsConstructor
@ToString
static class DemoObject {
private String name;
@Override
protected void finalize() throws Throwable {
System.out.println("finalize running DoSomething ..." + name);
}
}
static class CleanerTask implements Runnable {
private String name;
public CleanerTask(String name) {
this.name = name;
}
// do something before gc
@Override
public void run() {
System.out.println("CleanerTask running DoSomething ..." + name );
}
}
}
输出:
finalize running DoSomething ...demo0
CleanerTask running DoSomething ...thread_1
finalize running DoSomething ...demo2
CleanerTask running DoSomething ...thread_3
finalize running DoSomething ...demo4
CleanerTask running DoSomething ...thread_5
finalize running DoSomething ...demo6
CleanerTask running DoSomething ...thread_7
finalize running DoSomething ...demo8
...
可以看到,每次 finalize 总是比 Cleaner 先执行,不管你run几次,结果都一样,那么思考一下为什么?
=== 点击查看top目录 ===
=== 点击查看top目录 ===
class FinalReference<T> extends Reference<T> {
public FinalReference(T referent, ReferenceQueue<? super T> q) {
super(referent, q);
}
}
=== 点击查看top目录 ===
final class Finalizer extends FinalReference<Object>
Finalizer引用的对象被gc之前,jvm会把相应的Finalizer对象放入队列 queue
private static ReferenceQueue<Object> queue = new ReferenceQueue<>();
=== 关于Reference的四个状态,可以看图 ===
=== 点击查看top目录 ===
静态的Finalizer对象链,每=== 实例化 ===一个对象,这个队列就会插入=== add ===一个。
// 静态的Finalizer对象链
private static Finalizer unfinalized = null;
=== 点击查看top目录 ===
// 双端指针
private Finalizer
next = null,
prev = null;
=== 点击查看top目录 ===
private static final Object lock = new Object();
=== 点击查看top目录 ===
private Finalizer(Object finalizee) {
// 4.4.1 初始化
super(finalizee, queue);
// 4.5 往前面插入
add();
}
class FinalReference<T> extends Reference<T> {
public FinalReference(T referent, ReferenceQueue<? super T> q) {
super(referent, q);
}
}
=== 点击查看top目录 ===
/* Invoked by VM */
static void register(Object finalizee) {
new Finalizer(finalizee);
}
=== 点击查看top目录 ===
往队列 unfinalized 的头部插入
// 往头部插
private void add() {
synchronized (lock) {
if (unfinalized != null) {
this.next = unfinalized;
unfinalized.prev = this;
}
unfinalized = this;
}
}
=== 点击查看top目录 ===
往队列 unfinalized 的头部移除
// 从头部移除
private void remove() {
synchronized (lock) {
if (unfinalized == this) {
if (this.next != null) {
unfinalized = this.next;
} else {
unfinalized = this.prev;
}
}
if (this.next != null) {
this.next.prev = this.prev;
}
if (this.prev != null) {
this.prev.next = this.next;
}
// next 和 prev 都指向自己,表明已经被 remove 掉了,准备调用类重新复写的 finalize 方法
this.next = this; /* Indicates that this has been finalized */
this.prev = this;
}
}
=== 点击查看top目录 ===
private boolean hasBeenFinalized() {
return (next == this);
}
=== 点击查看top目录 ===
static {
ThreadGroup tg = Thread.currentThread().getThreadGroup();
for (ThreadGroup tgn = tg;
tgn != null;
tg = tgn, tgn = tg.getParent());
Thread finalizer = new FinalizerThread(tg);
finalizer.setPriority(Thread.MAX_PRIORITY - 2); // 特地让出了优先级,这个跟cleaner还不一样
finalizer.setDaemon(true); // 幽灵线程,这个跟 cleaner 一样
finalizer.start(); // 把线程给跑起来
}
这个静态代码块跟 === Reference的static代码块 ReferenceHandler=== 很相近 。
接下来看下内部类 FinalizerThread 是干什么的!!!
=== 点击查看top目录 ===
private static class FinalizerThread extends Thread {
// 这个参数用来判断该线程是否已经启动
private volatile boolean running;
FinalizerThread(ThreadGroup g) {
super(g, "Finalizer");
}
public void run() {
// in case of recursive call to run()
// 如果发生了递归调用则直接返回
if (running)
return;
// Finalizer thread starts before System.initializeSystemClass
// is called. Wait until JavaLangAccess is available
// Finalizer线程在 System.initializeSystemClass 被调用前启动
// 需要等到JVM已经初始化完成才能执行
// 4.9.1
while (!VM.isBooted()) {
// delay until VM completes initialization
// 延迟等待 JVM 完全初始化完毕
try {
VM.awaitBooted();
} catch (InterruptedException x) {
// ignore and continue
}
}
// 4.9.2
final JavaLangAccess jla = SharedSecrets.getJavaLangAccess(); // getter 直接看 Reference 类的 static 代码块
running = true;
// 4.9.3
for (;;) {
try {
// 将 Finalizer 从 queue 队列中拿出来然后调用完方法后释放
// Active -> pending -> enqueue -> 出队列,进行处理
Finalizer f = (Finalizer)queue.remove();
// 调用其runFinalizer方法,实质是要去调用该对象覆写的 finalize 方法
f.runFinalizer(jla);
} catch (InterruptedException x) {
// ignore and continue
// 这个地方要注意,你重写的 finalize 方法,里面抛出的异常,是直接忽略的
}
}
}
}
=== 点击查看top目录 ===
判断 JVM 是否已经启动,如果还没启动,那么 VM.awaitBooted() 等待 JVM 启动再说。
=== 点击查看top目录 ===
=== 点击查看top目录 ===
for (;;) {
try {
// 将 Finalizer 从 queue 队列中拿出来然后调用完方法后释放
// Active -> pending -> enqueue -> 出队列,进行处理
Finalizer f = (Finalizer)queue.remove();
// 调用其runFinalizer方法,实质是要去调用该对象覆写的 finalize 方法
f.runFinalizer(jla);
} catch (InterruptedException x) {
// ignore and continue
// 这个地方要注意,你重写的 finalize 方法,里面抛出的异常,是直接忽略的
}
}
=== 点击查看top目录 ===
=== 点击查看top目录 ===
// 执行 finalize 方法,然后进行GC回收
private void runFinalizer(JavaLangAccess jla) {
synchronized (this) {
// 只能执行1次,如果已经执行了。那么直接 return 回收
if (hasBeenFinalized()) return;
//执行 remove方法 ,从 unfinalized 链中拿掉该节点,然后返回出来,有点类似于 pop 操作
remove();
}
try {
// 拿到 指针指向的对象
Object finalizee = this.get();
if (finalizee != null && !(finalizee instanceof java.lang.Enum)) {
// 对象调用 finalize 方法
jla.invokeFinalize(finalizee);
/* Clear stack slot containing this variable, to decrease
the chances of false retention with a conservative GC */
finalizee = null; //设置为空
}
} catch (Throwable x) { }
// 4.9.5 解除强引用
super.clear();
}
=== 点击查看top目录 ===
public void clear() {
this.referent = null;
}
解除强引用。
=== 点击查看top目录 ===
JVM启动时,自动开启两个线程
=== 点击查看top目录 ===
/* Wormhole for calling java.lang.ref.Finalizer.runFinalization */
private static native void runFinalization0();
public void runFinalization() {
runFinalization0();
}
=== 点击查看top目录 ===
/* Called by Runtime.runFinalization() */
static void runFinalization() {
// JVM 是否启动
if (!VM.isBooted()) {
return;
}
forkSecondaryFinalizer(new Runnable() {
private volatile boolean running;
public void run() {
// in case of recursive call to run()
if (running)
return;
final JavaLangAccess jla = SharedSecrets.getJavaLangAccess();
running = true;
for (;;) {
Finalizer f = (Finalizer)queue.poll();
if (f == null) break;
f.runFinalizer(jla);
}
}
});
}
=== 点击查看top目录 ===
private static void forkSecondaryFinalizer(final Runnable proc) {
// 调用了AccessController.doPrivileged方法,这个方法的作用是使其内部的代码段获得更大的权限,可以在里面访问更多的资源。
AccessController.doPrivileged(
new PrivilegedAction<Void>() {
public Void run() {
ThreadGroup tg = Thread.currentThread().getThreadGroup();
for (ThreadGroup tgn = tg;
tgn != null;
tg = tgn, tgn = tg.getParent());
Thread sft = new Thread(tg, proc, "Secondary finalizer");
sft.start();
try {
sft.join();
} catch (InterruptedException x) {
Thread.currentThread().interrupt();
}
return null;
}});
}
=== 点击查看top目录 ===
/* Wormhole for invoking java.lang.ref.Finalizer.runAllFinalizers */
private static native void runAllFinalizers();
=== 点击查看top目录 ===
/* Invoked by java.lang.Shutdown */
static void runAllFinalizers() {
// JVM 是否启动
if (!VM.isBooted()) {
return;
}
forkSecondaryFinalizer(new Runnable() {
private volatile boolean running;
public void run() {
// in case of recursive call to run()
if (running)
return;
final JavaLangAccess jla = SharedSecrets.getJavaLangAccess();
running = true;
for (;;) {
Finalizer f;
synchronized (lock) {
f = unfinalized;
if (f == null) break;
unfinalized = f.next;
}
f.runFinalizer(jla);
}}});
}
=== 点击查看top目录 ===
/* Called by Runtime.runFinalization() */
static void runFinalization() {
...
for (;;) {
Finalizer f = (Finalizer)queue.poll();
if (f == null) break;
f.runFinalizer(jla);
}
...
}
/* Invoked by java.lang.Shutdown */
static void runAllFinalizers() {
...
for (;;) {
Finalizer f;
synchronized (lock) {
f = unfinalized;
if (f == null) break;
unfinalized = f.next;
}
f.runFinalizer(jla);
}
...
}
=== 点击查看top目录 ===
上一章节:【JAVA Reference】Cleaner 在堆外内存DirectByteBuffer中的应用(五)