FinalizableReference

/*
* Copyright (C) 2007 The Guava Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/ package com.google.common.base; /**
* Implemented by references that have code to run after garbage collection of their referents.
*
* 由一些reference实现,这些reference是具有可以在他们的referents被垃圾回收后执行的代码的referent
*
* @see FinalizableReferenceQueue
* @author Bob Lee
* @since 2.0 (imported from Google Collections Library)
*/
public interface FinalizableReference {
/**
* Invoked on a background thread after the referent has been garbage collected unless security
* restrictions prevented starting a background thread, in which case this method is invoked when
* new references are created.
*
* 当referent被回收后调用一个后台线程,除非安全策略阻止启动这个安全线程,此时这个方法会在一个新的reference创建后被调用
*/
void finalizeReferent();
}

FinalizablePhantomReference

/*
* Copyright (C) 2007 The Guava Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/ package com.google.common.base; import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue; /**
* Phantom reference with a {@code finalizeReferent()} method which a background thread invokes
* after the garbage collector reclaims the referent. This is a simpler alternative to using a
* {@link ReferenceQueue}.
*
* 一个有可以在垃圾收集器回收referent后被后台线程调用的finalizeReferent()方法的虚引用
* 这是一个对ReferenceQueue更简单的替代
*
* <p>Unlike a normal phantom reference, this reference will be cleared automatically.
* 不像一个普通的虚引用,这个引用会自动清理
*
* @author Bob Lee
* @since 2.0 (imported from Google Collections Library)
*/
public abstract class FinalizablePhantomReference<T> extends PhantomReference<T>
implements FinalizableReference {
/**
* Constructs a new finalizable phantom reference.
*
* @param referent to phantom reference
* @param queue that should finalize the referent
*/
protected FinalizablePhantomReference(T referent, FinalizableReferenceQueue queue) {
super(referent, queue.queue);
queue.cleanUp();
}
}

FinalizableReferenceQueue

/*
* Copyright (C) 2007 The Guava Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/ package com.google.common.base; import com.google.common.annotations.VisibleForTesting; import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.logging.Level;
import java.util.logging.Logger; /**
* A reference queue with an associated background thread that dequeues references and invokes
* {@link FinalizableReference#finalizeReferent()} on them.
*
* 一个和后台线程关联的引用队列,他可以将引用出队并调用他们的FinalizableReference#finalizeReferent()方法
*
* <p>Keep a strong reference to this object until all of the associated referents have been
* finalized. If this object is garbage collected earlier, the backing thread will not invoke {@code
* finalizeReferent()} on the remaining references.
*
* 保留一个强引用给这个对象知道所有的关联引用都被终结.加入这个对象过早地被垃圾回收,后台线程将不会再调用剩余引用的finalizeReferent()
*
* @author Bob Lee
* @since 2.0 (imported from Google Collections Library)
*/
public class FinalizableReferenceQueue {
/*
* The Finalizer thread keeps a phantom reference to this object. When the client (for example, a
* map built by MapMaker) no longer has a strong reference to this object, the garbage collector
* will reclaim it and enqueue the phantom reference. The enqueued reference will trigger the
* Finalizer to stop.
*
* Finalizer 线程持有这个对象的虚引用.当客户端(比如一个由MapMaker创建的Map)不再有这个对象的强引用时
* 垃圾收集器将会回收它并将他的虚引用入队.这个入队的虚引用将会触发Finalizer的终止
*
* If this library is loaded in the system class loader, FinalizableReferenceQueue can load
* Finalizer directly with no problems.
*
* 假如这个lib是由system class loader加载的,FinalizableReferenceQueue可以直接加载Finalizer
*
* If this library is loaded in an application class loader, it's important that Finalizer not
* have a strong reference back to the class loader. Otherwise, you could have a graph like this:
*
* 假如这个lib是由application class loader加载的,很重要的一点是Finalizer不会持有这个class loader的强引用.
* 另外,你可以有个图,如下:
*
* Finalizer Thread runs instance of -> Finalizer.class loaded by -> Application class loader
* which loaded -> ReferenceMap.class which has a static -> FinalizableReferenceQueue instance
*
* Finalizer Thread 运行一个 -> Finalizer.class的实例这个Finalizer.class被 -> Application class loader 加载 ->
* Application class loader 加载的 ReferenceMap.class, 这个ReferenceMap持有一个静态的 -> FinalizableReferenceQueue实例
*
* Even if no other references to classes from the application class loader remain, the Finalizer
* thread keeps an indirect strong reference to the queue in ReferenceMap, which keeps the
* Finalizer running, and as a result, the application class loader can never be reclaimed.
*
* 即使没有别的从application class loader中来的class的引用留下,Finalizer thread 也会保持一个在ReferenceMap
* 中的这个queue的间接强引用, 这样可以保持Finalizer持续运行, 结论就是application class loader永远不会被垃圾回收
*
* This means that dynamically loaded web applications and OSGi bundles can't be unloaded.
*
* 这意味着动态加载的web应用和OSGi bundles不能被卸载
*
* If the library is loaded in an application class loader, we try to break the cycle by loading
* Finalizer in its own independent class loader:
*
* 假如这个lib是被 application class loader 加载的,我们试图通过在他自己独立的class loader里加载Finalizer
* 来破坏这个循环
*
* System class loader -> Application class loader -> ReferenceMap -> FinalizableReferenceQueue
* -> etc. -> Decoupled class loader -> Finalizer
*
* Now, Finalizer no longer keeps an indirect strong reference to the static
* FinalizableReferenceQueue field in ReferenceMap. The application class loader can be reclaimed
* at which point the Finalizer thread will stop and its decoupled class loader can also be
* reclaimed.
*
* 现在, Finalizer不在持有ReferenceMap中的static 属性FinalizableReferenceQueue的强引用了,application class loader
* 可以在Finalizer线程停止的时候被回收,并且他的解耦的class loader也可以被回收
*
* If any of this fails along the way, we fall back to loading Finalizer directly in the
* application class loader.
*
* 假如这种方法失败了,我们会回到使用直接在application class loader加载Finalizer的方式
*/ private static final Logger logger = Logger.getLogger(FinalizableReferenceQueue.class.getName()); private static final String FINALIZER_CLASS_NAME = "com.google.common.base.internal.Finalizer"; /** Reference to Finalizer.startFinalizer(). */
/** Finalizer.startFinalizer(). 方法的引用 */
private static final Method startFinalizer;
static {
// TODO 分别使用SystemLoader(), DecoupledLoader, DirectLoader()来加载Finalizer
Class<?> finalizer = loadFinalizer(
new SystemLoader(), new DecoupledLoader(), new DirectLoader());
startFinalizer = getStartFinalizer(finalizer);
} /**
* The actual reference queue that our background thread will poll.
*
* 后台线程Finalizer用来clean reference的queue
*/
final ReferenceQueue<Object> queue; /**
* Whether or not the background thread started successfully.
*
* 标记后台线程是否启动成功
*/
final boolean threadStarted; /**
* Constructs a new queue.
*
* 构造方法
*/
@SuppressWarnings("unchecked")
public FinalizableReferenceQueue() {
// We could start the finalizer lazily, but I'd rather it blow up early.
// 我们会延迟启动finalizer, 但我宁愿他早点启动
ReferenceQueue<Object> queue;
boolean threadStarted = false;
try {
// TODO 这里invoke(null)是怎么做到的
queue = (ReferenceQueue<Object>)
startFinalizer.invoke(null, FinalizableReference.class, this);
threadStarted = true;
} catch (IllegalAccessException impossible) {
throw new AssertionError(impossible); // startFinalizer() is public
} catch (Throwable t) {
logger.log(Level.INFO, "Failed to start reference finalizer thread."
+ " Reference cleanup will only occur when new references are created.", t);
queue = new ReferenceQueue<Object>();
} this.queue = queue;
this.threadStarted = threadStarted;
} /**
* Repeatedly dequeues references from the queue and invokes {@link
* FinalizableReference#finalizeReferent()} on them until the queue is empty. This method is a
* no-op if the background thread was created successfully.
*
* 当finalizer线程启动失败的时候,手动调用cleanUp()方法来清理queue里的reference
*/
void cleanUp() {
if (threadStarted) {
return;
} Reference<?> reference;
while ((reference = queue.poll()) != null) {
/*
* This is for the benefit of phantom references. Weak and soft references will have already
* been cleared by this point.
*
* 这个清理的方法跟Finalizer里的cleanUp()是一样的
*/
reference.clear();
try {
((FinalizableReference) reference).finalizeReferent();
} catch (Throwable t) {
logger.log(Level.SEVERE, "Error cleaning up after reference.", t);
}
}
} /**
* Iterates through the given loaders until it finds one that can load Finalizer.
*
* 使用一组loader遍历加载finalizer直到加载成功
*
* @return Finalizer.class
*/
private static Class<?> loadFinalizer(FinalizerLoader... loaders) {
for (FinalizerLoader loader : loaders) {
Class<?> finalizer = loader.loadFinalizer();
if (finalizer != null) {
return finalizer;
}
} throw new AssertionError();
} /**
* Loads Finalizer.class.
*
* 顶一个load Finalizer的加载器
*/
interface FinalizerLoader { /**
* Returns Finalizer.class or null if this loader shouldn't or can't load it.
*
* 加载成功返回Finalizer.class
*
* @throws SecurityException if we don't have the appropriate privileges
*/
Class<?> loadFinalizer();
} /**
* Tries to load Finalizer from the system class loader. If Finalizer is in the system class path,
* we needn't create a separate loader.
*
* 尝试使用system class loader来加载Finalizer
* 假如Finalizer已经在system class path中,则不需要再创建一个分离的loader
*/
static class SystemLoader implements FinalizerLoader {
// This is used by the ClassLoader-leak test in FinalizableReferenceQueueTest to disable
// 这个变量用来给 FinalizableReferenceQueueTest 做 ClassLoader-leak 测试用
// finding Finalizer on the system class path even if it is there.
// 在system class path中寻找Finalizer
@VisibleForTesting // 标记这是一个测试变量的annotation
static boolean disabled; @Override
public Class<?> loadFinalizer() {
if (disabled) {
return null;
}
ClassLoader systemLoader;
try {
systemLoader = ClassLoader.getSystemClassLoader();
} catch (SecurityException e) {
logger.info("Not allowed to access system class loader.");
return null;
}
if (systemLoader != null) {
try {
return systemLoader.loadClass(FINALIZER_CLASS_NAME);
} catch (ClassNotFoundException e) {
// Ignore. Finalizer is simply in a child class loader.
// Finalizer在child class loader的情况
return null;
}
} else {
return null;
}
}
} /**
* Try to load Finalizer in its own class loader. If Finalizer's thread had a direct reference to
* our class loader (which could be that of a dynamically loaded web application or OSGi bundle),
* it would prevent our class loader from getting garbage collected.
*
* 尝试使用Finalizer自己的class loader来加载Finalizer, 假如Finalizer线程有一个对我们的class loader的直接引用
* (这可能是一个动态加载的web程序或者OSGi bundle)
* 他将会阻止我们的class loader被垃圾回收
*/
static class DecoupledLoader implements FinalizerLoader {
private static final String LOADING_ERROR = "Could not load Finalizer in its own class loader."
+ "Loading Finalizer in the current class loader instead. As a result, you will not be able"
+ "to garbage collect this class loader. To support reclaiming this class loader, either"
+ "resolve the underlying issue, or move Google Collections to your system class path."; @Override
public Class<?> loadFinalizer() {
try {
/*
* We use URLClassLoader because it's the only concrete class loader implementation in the
* JDK. If we used our own ClassLoader subclass, Finalizer would indirectly reference this
* class loader:
*
* 我们使用 URLClassLoader因为它是JDK中唯一各一个class loader实现
* 假如我们使用自己的ClassLoader子类, Finalizer将会有一个间接引用到this class loader
*
* Finalizer.class -> CustomClassLoader -> CustomClassLoader.class -> This class loader
*
* System class loader will (and must) be the parent.
*
* System class loader 将会是(也必须是) 父 class loader
*/
ClassLoader finalizerLoader = newLoader(getBaseUrl());
return finalizerLoader.loadClass(FINALIZER_CLASS_NAME);
} catch (Exception e) {
logger.log(Level.WARNING, LOADING_ERROR, e);
return null;
}
} /**
* Gets URL for base of path containing Finalizer.class.
*
* 获取包含Finalizer.class的基础路径的URL
*/
URL getBaseUrl() throws IOException {
// Find URL pointing to Finalizer.class file.
// 找到Finalizer.class文件的URL
String finalizerPath = FINALIZER_CLASS_NAME.replace('.', '/') + ".class";
URL finalizerUrl = getClass().getClassLoader().getResource(finalizerPath);
if (finalizerUrl == null) {
throw new FileNotFoundException(finalizerPath);
} // Find URL pointing to base of class path.
// 找到class path的base URL
String urlString = finalizerUrl.toString();
if (!urlString.endsWith(finalizerPath)) {
throw new IOException("Unsupported path style: " + urlString);
}
// 获取Finalizer.class的base路径字符串
urlString = urlString.substring(0, urlString.length() - finalizerPath.length());
// 返回一个以finalizerUrl为域名,base urlString为后缀的URL
return new URL(finalizerUrl, urlString);
} /** Creates a class loader with the given base URL as its classpath. */
/** 使用指定的URL创建一个class loader */
URLClassLoader newLoader(URL base) {
// We use the bootstrap class loader as the parent because Finalizer by design uses
// only standard Java classes. That also means that FinalizableReferenceQueueTest
// doesn't pick up the wrong version of the Finalizer class. // 我们使用bootstrap class loader来作为父loader因为Finalizer的设计是使用标准java类设计的
// 也就是说FinalizableReferenceQueueTest无法找出错误的Finalizer class版本
return new URLClassLoader(new URL[] {base}, null);
}
} /**
* Loads Finalizer directly using the current class loader. We won't be able to garbage collect
* this class loader, but at least the world doesn't end.
*
* 使用当前Application Class Loader直接加载Finalizer,这样我们将不能呢对这个class loader进行垃圾回收
* 但至少这个世界不会毁灭...
*/
static class DirectLoader implements FinalizerLoader {
@Override
public Class<?> loadFinalizer() {
try {
return Class.forName(FINALIZER_CLASS_NAME);
} catch (ClassNotFoundException e) {
throw new AssertionError(e);
}
}
} /**
* Looks up Finalizer.startFinalizer().
*
* 返回Finalizer的startFinalizer()方法
*/
static Method getStartFinalizer(Class<?> finalizer) {
try {
return finalizer.getMethod("startFinalizer", Class.class, Object.class);
} catch (NoSuchMethodException e) {
throw new AssertionError(e);
}
}
}

FinalizableReference, FinalizablePhantomReference, FinalizableReferenceQueue的更多相关文章

  1. Guava Finalizer

    /* * Copyright (C) 2008 The Guava Authors Licensed under the Apache License, Version 2.0 (the " ...

  2. ReferenceQueue的使用

    转:http://www.iflym.com/index.php/java-programe/201407140001.html 1 何为ReferenceQueue 在java的引用体系中,存在着强 ...

随机推荐

  1. oj提交时常见错误归纳

    Presentation Error: 常见的PE错误应该有以下的几种情况: 每行输出之后有空行 每两行输出之间有空行 一行中,每个输出数字(或字符串,等)之间有空格 一行中,每个输出数字(或字符串, ...

  2. 少走弯路,一个老程序猿谈PHP职业发展规划

    PHP是一个使用者非常多的开发语言,但在每个领域里的开发侧重点有所不同互联网方面,在稳定的基础上,更注重性能.高并发,高负载的处理. PHP职业发展规划一般有三条路线,一条技能专精发展路线.另两条,是 ...

  3. Java文件类

    在Java语言中,无论是目录还是文件,都抽象成java.io.File类 直接上示例吧 java,io,File的常用操作 删除.创建 因为我的e盘里面是没有这个文件的,所以不存在I哦 创建文件: 获 ...

  4. commonjs,amd,cmd

    在某些库中,经常会看到函数最前面有一个分号.其实是为了防止自动化工具拼接js时,如果前面的js文件的结尾处忘了加分号,拼接出来的代码容易挂,加分号这种行为属于防御式编程. 一个模块就是实现特定功能的文 ...

  5. [ 转载 ] Http详解2

    HTTP是一个属于应用层的面向对象的协议,由于其简捷.快速的方式,适用于分布式超媒体信息系统 | |目录 1引言 2一.HTTP协议详解之URL篇 3二.HTTP协议详解之请求篇 4三.HTTP协议详 ...

  6. openQPA[01]初次认识与使用

    开源项目QPA 1.项目主页:[http://protocol.sinaapp.com/] 2.项目介绍: 3.运行项目: (1)安装python2.7,并安装PyQt4.   下载地址[https: ...

  7. jsp的9大内置对象和4大作用域

  8. 关于输出螺旋矩阵的demo

    输出类似 1 2 3 8 9 4 7 6 5 主要难点是如何找到表示的算法 我的理解是,先生成一个n*n的矩阵,然后再往里面塞数字,而塞的方法分别有四种:由左往右,由上往下,由右往左,由下往上,没塞完 ...

  9. BZOJ5020 [THUWC 2017]在美妙的数学王国中畅游LCT

    题意很明显是要用LCT来维护森林 难点在于如何处理函数之间的关系 我们可以根据题目给的提示关于泰勒展开的式子 将三种函数变成泰勒展开的形式 因为$x∈[0,1]$ 所以我们可以将三个函数在$x_0=0 ...

  10. IEEEXtreme Practice Community Xtreme9.0 - Digit Fun!

    Xtreme9.0 - Digit Fun! 题目连接: https://www.hackerrank.com/contests/ieeextreme-challenges/challenges/di ...