netty 资源泄漏探测器

netty 通道接口定义: http://donald-draper.iteye.com/blog/2392740
netty 抽象通道初始化: http://donald-draper.iteye.com/blog/2392801
netty 抽象Unsafe定义: http://donald-draper.iteye.com/blog/2393053
netty 通道Outbound缓冲区: http://donald-draper.iteye.com/blog/2393098
netty 抽象通道后续: http://donald-draper.iteye.com/blog/2393166
netty 抽象nio通道: http://donald-draper.iteye.com/blog/2393269
netty 抽象nio字节通道: http://donald-draper.iteye.com/blog/2393323
netty 抽象nio消息通道: http://donald-draper.iteye.com/blog/2393364
netty NioServerSocketChannel解析: http://donald-draper.iteye.com/blog/2393443
netty 通道配置接口定义: http://donald-draper.iteye.com/blog/2393484
netty 默认通道配置初始化: http://donald-draper.iteye.com/blog/2393504
netty 默认通道配置后续: http://donald-draper.iteye.com/blog/2393510
netty 字节buf定义: http://donald-draper.iteye.com/blog/2393813
引言
上一篇文章我们看了字节buf接口的定义,先来回顾一下:
对象引用计数器ReferenceCounted,主要记录对象的引用数量,当引用数量为0时,表示可以回收对象,在调试模式下,如果发现对象出现内存泄漏,可以用touch方法记录操作的相关信息,通过ResourceLeakDetector获取操作的相关信息,以便分析内存泄漏的原因。

字节缓存ByteBuf继承了对象引用计数器ReferenceCounted,拥有一个最大容量限制,如果用户尝试用 #capacity(int)和 #ensureWritable(int)方法,增加buf容量超过最大容量,将会抛出非法参数异常;字节buf有两个索引,一个为读索引readerIndex,一个为写索引writerIndex,读索引不能大于写索引,写索引不能小于读索引,buf可读字节数为writerIndex - readerIndex,buf可写字节数为capacity - writerIndex,buf可写的最大字节数为maxCapacity - writerIndex;

可以使用markReader/WriterIndex标记当前buf读写索引位置,resetReader/WriterIndex方法可以重回先前标记的索引位置;

当内存空间负载过度时,我们可以使用discardReadBytes丢弃一些数据,以节省空间;

我们可以使用ensureWritable检测当buf是否有足够的空间写数据;

提供了getBytes方法,可以将buf中的数据转移到目的ByteBuf,Byte数组,Nio字节buf ByteBuffer,OutputStream,聚集字节通道
GatheringByteChannel和文件通道FileChannel中,这些方法不会修改当前buf读写索引,具体是否修改目的对象索引或位置,见java doc 描述。

提供了setBytes方法,可以将源ByteBuf,Byte数组,Nio字节buf ByteBuffer,InputputStream,分散字节通道ScatteringByteChannel和文件通道FileChannel中的数据转移到当前buf中,这些方法不会修改当前buf的读写索引,至于源对象索引或位置,见java doc 描述。

提供了readBytes方法,可以将buf中的数据转移到目的ByteBuf,Byte数组,Nio字节buf ByteBuffer,OutputStream,聚集字节通道GatheringByteChannel和文件通道FileChannel中,这些方法具体会会修改当前buf读索引,至于会不会修改源对象索引或位置,见java doc 描述。

提供了writeBytes方法,可以将源ByteBuf,Byte数组,Nio字节buf ByteBuffer,
InputputStream,分散字节通道ScatteringByteChannel和文件通道FileChannel中的数据写到当前buf中,这些方法会修改当前buf的写索引,至于会不会修改源对象索引或位置,见java
doc 描述。


set*原始类型方法不会修改读写索引;
get*原始类型方法不会修改读写索引;

write*原始类型方法会修改写索引;
read*原始类型方法,会修改读索引;

字节buf中的set/get*方法不会修改当前buf的读写索引,而write*修改写索引,read*会修改读索引;

提供了copy,slice和retainSlice,duplicate和retainedDuplicate方法,用于拷贝,切割,复制当前buf数据,retained*方法会增加buf的
引用计数器;

提供nioBuffer和nioBuffers方法,用于包装当前buf可读数据为java nio ByteBuffer和ByteBuffer数组。

今天我们来看一下抽象字节buf的定义

/**
 * A skeletal implementation of a buffer.
 */
public abstract class AbstractByteBuf extends ByteBuf {
    private static final InternalLogger logger = InternalLoggerFactory.getInstance(AbstractByteBuf.class);
    private static final String PROP_MODE = "io.netty.buffer.bytebuf.checkAccessible";
    private static final boolean checkAccessible;

    static {
        checkAccessible = SystemPropertyUtil.getBoolean(PROP_MODE, true);
        if (logger.isDebugEnabled()) {
            logger.debug("-D{}: {}", PROP_MODE, checkAccessible);
        }
    }
    //内存泄漏探测器
    static final ResourceLeakDetector<ByteBuf> leakDetector =
            ResourceLeakDetectorFactory.instance().newResourceLeakDetector(ByteBuf.class);

    int readerIndex;//读索引
    int writerIndex;//写索引
    private int markedReaderIndex;//读索引标记
    private int markedWriterIndex;//写索引标记
    private int maxCapacity;//最大容量

    protected AbstractByteBuf(int maxCapacity) {
        if (maxCapacity < 0) {
            throw new IllegalArgumentException("maxCapacity: " + maxCapacity + " (expected: >= 0)");
        }
        this.maxCapacity = maxCapacity;
    }:
}

从上面来看,字节buf内部有两个索引,一个读索引,一个写索引,两个索引标记,即读写索引对应的标记,buf的最大容量为maxCapacity;buf的构造,主要是初始化最大容量。

在抽象字节buf的内部变量声明中有一个资源泄漏探测器,定义如下:
public abstract class AbstractByteBuf extends ByteBuf {

    //内存泄漏探测器
    static final ResourceLeakDetector<ByteBuf> leakDetector =
            ResourceLeakDetectorFactory.instance().newResourceLeakDetector(ByteBuf.class);
    ...
}

来看内存探测器工厂
//ResourceLeakDetectorFactory
/**
 * This static factory should be used to load {@link ResourceLeakDetector}s as needed
 */
public abstract class ResourceLeakDetectorFactory {
    private static final InternalLogger logger = InternalLoggerFactory.getInstance(ResourceLeakDetectorFactory.class);
    //默认资源泄漏探测器工厂
    private static volatile ResourceLeakDetectorFactory factoryInstance = new DefaultResourceLeakDetectorFactory();

    /**
     * Get the singleton instance of this factory class.
     *获取资源泄漏探测器工厂
     * @return the current {@link ResourceLeakDetectorFactory}
     */
    public static ResourceLeakDetectorFactory instance() {
        return factoryInstance;
    }

    /**
     * Set the factory's singleton instance. This has to be called before the static initializer of the
     * {@link ResourceLeakDetector} is called by all the callers of this factory. That is, before initializing a
     * Netty Bootstrap.
     *设置资源泄漏探测器工厂单例。此方法必须在素有的工作调用者,初始化ResourceLeakDetector前调用,
     即在netty的引导启动配置前初始化
     * @param factory the instance that will become the current {@link ResourceLeakDetectorFactory}'s singleton
     */
    public static void setResourceLeakDetectorFactory(ResourceLeakDetectorFactory factory) {
        factoryInstance = ObjectUtil.checkNotNull(factory, "factory");
    }

    /**
     * Returns a new instance of a {@link ResourceLeakDetector} with the given resource class.
     *使用给定的资源类,创建要给资源泄漏探测器
     * @param resource the resource class used to initialize the {@link ResourceLeakDetector}
     * @param <T> the type of the resource class
     * @return a new instance of {@link ResourceLeakDetector}
     */
    public final <T> ResourceLeakDetector<T> newResourceLeakDetector(Class<T> resource) {
        return newResourceLeakDetector(resource, ResourceLeakDetector.DEFAULT_SAMPLING_INTERVAL);
    }
     /**
     * Returns a new instance of a {@link ResourceLeakDetector} with the given resource class.
     *使用给定的资源类和采样间隔,创建要给资源泄漏探测器
     * @param resource the resource class used to initialize the {@link ResourceLeakDetector}
     * @param samplingInterval the interval on which sampling takes place
     * @param <T> the type of the resource class
     * @return a new instance of {@link ResourceLeakDetector}
     */
    @SuppressWarnings("deprecation")
    public <T> ResourceLeakDetector<T> newResourceLeakDetector(Class<T> resource, int samplingInterval) {
        return newResourceLeakDetector(resource, ResourceLeakDetector.DEFAULT_SAMPLING_INTERVAL, Long.MAX_VALUE);
    }
    /**
     * @deprecated Use {@link #newResourceLeakDetector(Class, int)} instead.
     * <p>
     * Returns a new instance of a {@link ResourceLeakDetector} with the given resource class.
     *待子类扩展
     * @param resource the resource class used to initialize the {@link ResourceLeakDetector}
     * @param samplingInterval the interval on which sampling takes place,采样间隔
     * @param maxActive This is deprecated and will be ignored. 此参数已经丢弃,将会被忽略
     * @param <T> the type of the resource class 资源类,类型
     * @return a new instance of {@link ResourceLeakDetector}
     */
    @Deprecated
    public abstract <T> ResourceLeakDetector<T> newResourceLeakDetector(
            Class<T> resource, int samplingInterval, long maxActive);

    /**
     * Default implementation that loads custom leak detector via system property
     默认资源泄漏探测器工厂
     */
    private static final class DefaultResourceLeakDetectorFactory extends ResourceLeakDetectorFactory {
        private final Constructor<?> obsoleteCustomClassConstructor;
        private final Constructor<?> customClassConstructor;

        DefaultResourceLeakDetectorFactory() {
            String customLeakDetector;
            try {
	        //在当前线程相同访问控制权限下,获取系统io.netty.customResourceLeakDetector属性配置
                customLeakDetector = AccessController.doPrivileged(new PrivilegedAction<String>() {
                    @Override
                    public String run() {
                        return SystemPropertyUtil.get("io.netty.customResourceLeakDetector");
                    }
                });
            } catch (Throwable cause) {
                logger.error("Could not access System property: io.netty.customResourceLeakDetector", cause);
                customLeakDetector = null;
            }
            if (customLeakDetector == null) {
	        //如果系统泄漏测器配置为空,则obsoleteCustom和custom构造为空
                obsoleteCustomClassConstructor = customClassConstructor = null;
            } else {
	        //否则初始泄漏探测器构造
                obsoleteCustomClassConstructor = obsoleteCustomClassConstructor(customLeakDetector);
                customClassConstructor = customClassConstructor(customLeakDetector);
            }
        }

        private static Constructor<?> obsoleteCustomClassConstructor(String customLeakDetector) {
            try {
	        //加载泄漏探测器类
                final Class<?> detectorClass = Class.forName(customLeakDetector, true,
                        PlatformDependent.getSystemClassLoader());

                if (ResourceLeakDetector.class.isAssignableFrom(detectorClass)) {
		    //构造资源泄漏探测器
                    return detectorClass.getConstructor(Class.class, int.class, long.class);
                } else {
                    logger.error("Class {} does not inherit from ResourceLeakDetector.", customLeakDetector);
                }
            } catch (Throwable t) {
                logger.error("Could not load custom resource leak detector class provided: {}",
                        customLeakDetector, t);
            }
            return null;
        }
        
        private static Constructor<?> customClassConstructor(String customLeakDetector) {
            try {
	        //加载泄漏探测器类
                final Class<?> detectorClass = Class.forName(customLeakDetector, true,
                        PlatformDependent.getSystemClassLoader());
                //构造资源泄漏探测器
                if (ResourceLeakDetector.class.isAssignableFrom(detectorClass)) {
                    return detectorClass.getConstructor(Class.class, int.class);
                } else {
                    logger.error("Class {} does not inherit from ResourceLeakDetector.", customLeakDetector);
                }
            } catch (Throwable t) {
                logger.error("Could not load custom resource leak detector class provided: {}",
                        customLeakDetector, t);
            }
            return null;
        }
	//根据资源类和采样间隔,创建资源泄漏探测器
        @Override
        public <T> ResourceLeakDetector<T> newResourceLeakDetector(Class<T> resource, int samplingInterval) {
            if (customClassConstructor != null) {
                try {
                    @SuppressWarnings("unchecked")
		    //使用customClassConstructor创建资源泄漏探测器
                    ResourceLeakDetector<T> leakDetector =
                            (ResourceLeakDetector<T>) customClassConstructor.newInstance(resource, samplingInterval);
                    logger.debug("Loaded custom ResourceLeakDetector: {}",
                            customClassConstructor.getDeclaringClass().getName());
                    return leakDetector;
                } catch (Throwable t) {
                    logger.error(
                            "Could not load custom resource leak detector provided: {} with the given resource: {}",
                            customClassConstructor.getDeclaringClass().getName(), resource, t);
                }
            }
            //直接创建资源泄漏探测器ResourceLeakDetector
            ResourceLeakDetector<T> resourceLeakDetector = new ResourceLeakDetector<T>(resource, samplingInterval);
            logger.debug("Loaded default ResourceLeakDetector: {}", resourceLeakDetector);
            return resourceLeakDetector;
        }
        @SuppressWarnings("deprecation")
        @Override
        public <T> ResourceLeakDetector<T> newResourceLeakDetector(Class<T> resource, int samplingInterval,
                                                                   long maxActive) {
            if (obsoleteCustomClassConstructor != null) {
                try {
		    //使用obsoleteCustomClassConstructor创建资源泄漏探测器
                    @SuppressWarnings("unchecked")
                    ResourceLeakDetector<T> leakDetector =
                            (ResourceLeakDetector<T>) obsoleteCustomClassConstructor.newInstance(
                                    resource, samplingInterval, maxActive);
                    logger.debug("Loaded custom ResourceLeakDetector: {}",
                            obsoleteCustomClassConstructor.getDeclaringClass().getName());
                    return leakDetector;
                } catch (Throwable t) {
                    logger.error(
                            "Could not load custom resource leak detector provided: {} with the given resource: {}",
                            obsoleteCustomClassConstructor.getDeclaringClass().getName(), resource, t);
                }
            }
            //直接创建资源泄漏探测器ResourceLeakDetector
            ResourceLeakDetector<T> resourceLeakDetector = new ResourceLeakDetector<T>(resource, samplingInterval,
            logger.debug("Loaded default ResourceLeakDetector: {}", resourceLeakDetector);
            return resourceLeakDetector;
        }

        
    }
}

从上面可以看出,默认的资源泄漏探测器工厂创建的资源泄漏探测器类型ResourceLeakDetector。


public class ResourceLeakDetector<T> {

    private static final String PROP_LEVEL_OLD = "io.netty.leakDetectionLevel";
    private static final String PROP_LEVEL = "io.netty.leakDetection.level";
    private static final Level DEFAULT_LEVEL = Level.SIMPLE;//默认探测登记

    private static final String PROP_MAX_RECORDS = "io.netty.leakDetection.maxRecords";
    private static final int DEFAULT_MAX_RECORDS = 4;//默认最大的资源泄漏记录线索数
    private static final int MAX_RECORDS;//最大的资源泄漏记录线索数

    /**
     * Represents the level of resource leak detection.
     资源泄漏等级
     */
    public enum Level {
        /**
         * Disables resource leak detection.
	 关闭资源泄漏探测
         */
        DISABLED,
        /**
         * Enables simplistic sampling resource leak detection which reports there is a leak or not,
         * at the cost of small overhead (default).
	 开启简单的采样资源泄漏探测,仅仅已少量的负载为代价报告是否为泄漏对象
         */
        SIMPLE,
        /**
         * Enables advanced sampling resource leak detection which reports where the leaked object was accessed
         * recently at the cost of high overhead.
	 开启高级采样泄漏探测,将会以高负载为代价,报告最近泄漏对象访问的地方
         */
        ADVANCED,
        /**
         * Enables paranoid resource leak detection which reports where the leaked object was accessed recently,
         * at the cost of the highest possible overhead (for testing purposes only).
	 开启终极采样泄漏探测,将会以高级负载为代价,报告最近泄漏对象访问的地方
         */
        PARANOID;

        /**
         * Returns level based on string value. Accepts also string that represents ordinal number of enum.
         *返回泄漏探测等级字符串。同时接受表示enum原始序号的字符串。
	 即根据等级字符串,返回对应的泄漏探测等级
         * @param levelStr - level string : DISABLED, SIMPLE, ADVANCED, PARANOID. Ignores case.
         * @return corresponding level or SIMPLE level in case of no match.
         */
        static Level parseLevel(String levelStr) {
            String trimmedLevelStr = levelStr.trim();
            for (Level l : values()) {
                if (trimmedLevelStr.equalsIgnoreCase(l.name()) || trimmedLevelStr.equals(String.valueOf(l.ordinal()))) {
                    return l;
                }
            }
            return DEFAULT_LEVEL;
        }
    }

    private static Level level; //当前static资源泄漏等级

    private static final InternalLogger logger = InternalLoggerFactory.getInstance(ResourceLeakDetector.class);
    //初始化资源泄漏探测状态及探测等级
    static {
        final boolean disabled;
	//获取系统资源泄漏探测配置,判断是否开启资源探测
        if (SystemPropertyUtil.get("io.netty.noResourceLeakDetection") != null) {
            disabled = SystemPropertyUtil.getBoolean("io.netty.noResourceLeakDetection", false);
            logger.debug("-Dio.netty.noResourceLeakDetection: {}", disabled);
            logger.warn(
                    "-Dio.netty.noResourceLeakDetection is deprecated. Use '-D{}={}' instead.",
                    PROP_LEVEL, DEFAULT_LEVEL.name().toLowerCase());
        } else {
            disabled = false;
        }
        //关闭,则等级为DISABLED,否则为默认等级
        Level defaultLevel = disabled? Level.DISABLED : DEFAULT_LEVEL;

        // First read old property name
        String levelStr = SystemPropertyUtil.get(PROP_LEVEL_OLD, defaultLevel.name());

        // If new property name is present, use it
        levelStr = SystemPropertyUtil.get(PROP_LEVEL, levelStr);
        Level level = Level.parseLevel(levelStr);

        MAX_RECORDS = SystemPropertyUtil.getInt(PROP_MAX_RECORDS, DEFAULT_MAX_RECORDS);

        ResourceLeakDetector.level = level;
        if (logger.isDebugEnabled()) {
            logger.debug("-D{}: {}", PROP_LEVEL, level.name().toLowerCase());
            logger.debug("-D{}: {}", PROP_MAX_RECORDS, MAX_RECORDS);
        }
    }

    // Should be power of two. 默认采样间隔
    static final int DEFAULT_SAMPLING_INTERVAL = 128;

    

    /** the collection of active resources  激活资源集合*/
    private final ConcurrentMap<DefaultResourceLeak, LeakEntry> allLeaks = PlatformDependent.newConcurrentHashMap();
    //资源写对象引用队列
    private final ReferenceQueue<Object> refQueue = new ReferenceQueue<Object>();
    //资源泄漏信息报告
    private final ConcurrentMap<String, Boolean> reportedLeaks = PlatformDependent.newConcurrentHashMap();
    private final String resourceType;//资源类型
    private final int samplingInterval;//采样间隔
}

从上面可以看出,资源泄漏探测器,探测等级有四种,关闭DISABLED,SIMPLE简单,高级ADVANCED,终极PARANOID,SIMPLE开启简单的采样资源泄漏探测,仅仅已少量的负载为代价报告是否为泄漏对象;ADVANCED开启高级采样泄漏探测,将会以高负载为代价,报告最近泄漏对象访问的地方;PARANOID开启终极采样泄漏探测,将会以高级负载为代价,报告最近泄漏对象访问的地方(仅仅测试);开启资源探测的情况下,默认等级为SIMPLE。资源探测器内部有一个探测等级和采样间隔,资源类型,泄漏报告Map( ConcurrentMap<String, Boolean>),
激活资源集合ConcurrentMap<DefaultResourceLeak, LeakEntry>,

再来看构造
/**
 * @deprecated use {@link ResourceLeakDetectorFactory#newResourceLeakDetector(Class, int, long)}.
 根据资源类型创建资源泄漏探测器
 */
@Deprecated
public ResourceLeakDetector(Class<?> resourceType) {
    this(simpleClassName(resourceType));
}

/**
 * @deprecated use {@link ResourceLeakDetectorFactory#newResourceLeakDetector(Class, int, long)}.
 根据资源类型名创建资源泄漏探测器
 */
@Deprecated
public ResourceLeakDetector(String resourceType) {
    this(resourceType, DEFAULT_SAMPLING_INTERVAL, Long.MAX_VALUE);
}

/**
 * @deprecated Use {@link ResourceLeakDetector#ResourceLeakDetector(Class, int)}.
 此方法已丢弃,请使用#ResourceLeakDetector(Class, int)方法
 * <p>
 * This should not be used directly by users of {@link ResourceLeakDetector}.
 * Please use {@link ResourceLeakDetectorFactory#newResourceLeakDetector(Class)}
 * or {@link ResourceLeakDetectorFactory#newResourceLeakDetector(Class, int, long)}
 *用于不可直接调用此方法,请使用ResourceLeakDetectorFactory#newResourceLeakDetector(Class)
 或ResourceLeakDetectorFactory#newResourceLeakDetector(Class, int, long)方法
 * @param maxActive This is deprecated and will be ignored.
 */
@Deprecated
public ResourceLeakDetector(Class<?> resourceType, int samplingInterval, long maxActive) {
    this(resourceType, samplingInterval);
}

/**
 * This should not be used directly by users of {@link ResourceLeakDetector}.
 * Please use {@link ResourceLeakDetectorFactory#newResourceLeakDetector(Class)}
 * or {@link ResourceLeakDetectorFactory#newResourceLeakDetector(Class, int, long)}
 */
@SuppressWarnings("deprecation")
public ResourceLeakDetector(Class<?> resourceType, int samplingInterval) {
    this(simpleClassName(resourceType), samplingInterval, Long.MAX_VALUE);
}
/**
 * @deprecated use {@link ResourceLeakDetectorFactory#newResourceLeakDetector(Class, int, long)}.
 * <p>
 * @param maxActive This is deprecated and will be ignored.
 */
@Deprecated
public ResourceLeakDetector(String resourceType, int samplingInterval, long maxActive) {
    if (resourceType == null) {
        throw new NullPointerException("resourceType");
    }

    this.resourceType = resourceType;
    this.samplingInterval = samplingInterval;
}


从上面来看资源泄漏探测器构造,主要初始化资源类型名及探测间隔。

再来看开启资源泄漏探测功能和设置探测等级

/**
 * @deprecated Use {@link #setLevel(Level)} instead.
 开启资源泄漏探测
 */
@Deprecated
public static void setEnabled(boolean enabled) {
    setLevel(enabled? Level.SIMPLE : Level.DISABLED);
}

/**
 * Returns {@code true} if resource leak detection is enabled.
 判断是否开启资源泄漏探测
 */
public static boolean isEnabled() {
    //如果探测等级大于DISABLED,则开启
    return getLevel().ordinal() > Level.DISABLED.ordinal();
}

我们来看一下枚举的ordinal方法
//Enum
public abstract class Enum<E extends Enum<E>>
        implements Comparable<E>, Serializable {
    /**
     * The name of this enum constant, as declared in the enum declaration.
     * Most programmers should use the {@link #toString} method rather than
     * accessing this field.
     枚举名,一般使用#toString方法获取,而不是直接方法此field
     */
    private final String name;
    /**
     * The ordinal of this enumeration constant (its position
     * in the enum declaration, where the initial constant is assigned
     * an ordinal of zero).
     *枚举常量在定义中的位置
     * Most programmers will have no use for this field.  It is designed
     * for use by sophisticated enum-based data structures, such as
     * {@link java.util.EnumSet} and {@link java.util.EnumMap}.
     */
    private final int ordinal;

    /**
     * Returns the name of this enum constant, exactly as declared in its
     * enum declaration.
     *
     * <b>Most programmers should use the {@link #toString} method in
     * preference to this one, as the toString method may return
     * a more user-friendly name.</b>  This method is designed primarily for
     * use in specialized situations where correctness depends on getting the
     * exact name, which will not vary from release to release.
     *
     * @return the name of this enum constant
     */
    public final String name() {
        return name;
    } 
    /**
     * Returns the ordinal of this enumeration constant (its position
     * in its enum declaration, where the initial constant is assigned
     * an ordinal of zero).
     *获取枚举常量在定义中的位置
     * Most programmers will have no use for this method.  It is
     * designed for use by sophisticated enum-based data structures, such
     * as {@link java.util.EnumSet} and {@link java.util.EnumMap}.
     *
     * @return the ordinal of this enumeration constant
     */
    public final int ordinal() {
        return ordinal;
    }
    ...
}

回到资源泄漏探测器
/**
 * Sets the resource leak detection level.
 设置资源泄漏探测等级
 */
public static void setLevel(Level level) {
    if (level == null) {
        throw new NullPointerException("level");
    }
    ResourceLeakDetector.level = level;
}

/**
 * Returns the current resource leak detection level.
 获取资源泄漏探测等级
 */
public static Level getLevel() {
    return level;
}

再来看其他方法:
/**
 * Creates a new {@link ResourceLeak} which is expected to be closed via {@link ResourceLeak#close()} when the
 * related resource is deallocated.
 *创建一个资源泄漏ResourceLeak,当相关资源释放时,希望通过ResourceLeak#close关闭,已丢弃
 * @return the {@link ResourceLeak} or {@code null}
 * @deprecated use {@link #track(Object)}
 */
@Deprecated
public final ResourceLeak open(T obj) {
    return track0(obj);
}

/**
 * Creates a new {@link ResourceLeakTracker} which is expected to be closed via
 * {@link ResourceLeakTracker#close(Object)} when the related resource is deallocated.
 *创建一个资源泄漏ResourceLeakTracker,当相关资源释放时,希望通过ResourceLeakTracker#close(Object)关闭对象
 * @return the {@link ResourceLeakTracker} or {@code null}
 */
public final ResourceLeakTracker<T> track(T obj) {
    return track0(obj);
}

private DefaultResourceLeak track0(T obj) {
...
}


为了便于理解我们先看ResourceLeak,ResourceLeakTracker,DefaultResourceLeak的定义

//ResourceLeak
package io.netty.util;

/**
 * @deprecated please use {@link ResourceLeakTracker} as it may lead to false-positives.
 已丢弃,请使用ResourceLeakTracker
 */
@Deprecated
public interface ResourceLeak {
    /**
     * Records the caller's current stack trace so that the {@link ResourceLeakDetector} can tell where the leaked
     * resource was accessed lastly. This method is a shortcut to {@link #record(Object) record(null)}.
     记录当前调用者栈追踪,以便资源泄漏探测器可以告诉,泄漏资源最近访问的地方。此方法为
     #record(Object)的快捷方式record(null)
     */
    void record();

    /**
     * Records the caller's current stack trace and the specified additional arbitrary information
     * so that the {@link ResourceLeakDetector} can tell where the leaked resource was accessed lastly.
     记录当前调用者栈追踪和额外的主观信息,以便资源泄漏探测器可以告诉,泄漏资源最近访问的地方。
     */
    void record(Object hint);

    /**
     * Close the leak so that {@link ResourceLeakDetector} does not warn about leaked resources.
     *关闭泄漏资源,以便资源泄漏探测器不在警告泄漏资源。
     * @return {@code true} if called first time, {@code false} if called already
     第一次调用返回true,否则为false
     */
    boolean close();
}

//ResourceLeakTracker

package io.netty.util;

public interface ResourceLeakTracker<T>  {

    /**
     * Records the caller's current stack trace so that the {@link ResourceLeakDetector} can tell where the leaked
     * resource was accessed lastly. This method is a shortcut to {@link #record(Object) record(null)}.
     记录当前调用者栈追踪,以便资源泄漏探测器可以告诉,泄漏资源最近访问的地方。此方法为
     #record(Object)的快捷方式record(null)
     */
    void record();

    /**
     * Records the caller's current stack trace and the specified additional arbitrary information
     * so that the {@link ResourceLeakDetector} can tell where the leaked resource was accessed lastly.
     记录当前调用者栈追踪和额外的主观信息,以便资源泄漏探测器可以告诉,泄漏资源最近访问的地方。
     */
    void record(Object hint);

    /**
     * Close the leak so that {@link ResourceLeakTracker} does not warn about leaked resources.
     * After this method is called a leak associated with this ResourceLeakTracker should not be reported.
     *关闭泄漏资源,以便资源泄漏探测器不在警告泄漏资源。在方法调用后,泄漏资源关联的ResourceLeakTracker不应该
     上报。
     * @return {@code true} if called first time, {@code false} if called already
     第一次调用返回true,否则为false
     */
    boolean close(T trackedObject);
}

从上面可以看出,资源泄漏追踪ResourceLeakTracker,主要定义了记录当前调用者栈追踪和额外的主观信息方法,以便资源泄漏探测器可以告诉,泄漏资源最近访问的地方;关闭泄漏资源方法,以便资源泄漏探测器不在警告泄漏资源。

//DefaultResourceLeak,为资源泄漏探测器ResourceLeakDetector的内部类
 @SuppressWarnings("deprecation")
    private final class DefaultResourceLeak extends PhantomReference<Object> implements ResourceLeakTracker<T>,
            ResourceLeak {
        private final String creationRecord;//创建记录
        private final Deque<String> lastRecords = new ArrayDeque<String>();//记录队列
        private final int trackedHash;
        private int removedRecords;移除记录计数器

        DefaultResourceLeak(Object referent) {
            super(referent, refQueue);

            assert referent != null;

            // Store the hash of the tracked object to later assert it in the close(...) method.
            // It's important that we not store a reference to the referent as this would disallow it from
            // be collected via the PhantomReference.
	    //获取对象引用hash值
            trackedHash = System.identityHashCode(referent);
            Level level = getLevel();
            if (level.ordinal() >= Level.ADVANCED.ordinal()) {
	        //如果探测等级大于ADVANCED,则创建记录
                creationRecord = newRecord(null, 3);
            } else {
                creationRecord = null;
            }
	    //将当前资源泄漏对象方法激活对象Map中
            allLeaks.put(this, LeakEntry.INSTANCE);
        }
}

我来看这一句:
//如果探测登记大于ADVANCED,则创建记录
creationRecord = newRecord(null, 3); 



static String newRecord(Object hint, int recordsToSkip) {
        StringBuilder buf = new StringBuilder(4096);

        // Append the hint first if available.
        if (hint != null) {
            buf.append("\tHint: ");
            // Prefer a hint string to a simple string form.
	    //如果对象时资源追踪线索,添加线索信息
            if (hint instanceof ResourceLeakHint) {
                buf.append(((ResourceLeakHint) hint).toHintString());
            } else {
                buf.append(hint);
            }
            buf.append(NEWLINE);
        }
        
        // Append the stack trace. 
        StackTraceElement[] array = new Throwable().getStackTrace();
        for (StackTraceElement e: array) {
	    //跳过前3个栈追踪
            if (recordsToSkip > 0) {
                recordsToSkip --;
            } else {
                String estr = e.toString();

                // Strip the noisy stack trace elements.
                boolean excluded = false;
		//剔除栈追踪噪音
                for (String exclusion: STACK_TRACE_ELEMENT_EXCLUSIONS) {
                    if (estr.startsWith(exclusion)) {
                        excluded = true;
                        break;
                    }
                }

                if (!excluded) {
                    buf.append('\t');
                    buf.append(estr);
                    buf.append(NEWLINE);
                }
            }
        }

        return buf.toString();
    }

//ResourceLeakHint
package io.netty.util;

/**
 * A hint object that provides human-readable message for easier resource leak tracking.
 资源泄漏线索,提供可读的资源泄漏追踪信息
 */
public interface ResourceLeakHint {
    /**
     * Returns a human-readable message that potentially enables easier resource leak tracking.
     */
    String toHintString();
}


private static final String[] STACK_TRACE_ELEMENT_EXCLUSIONS = {
        "io.netty.util.ReferenceCountUtil.touch(",
        "io.netty.buffer.AdvancedLeakAwareByteBuf.touch(",
        "io.netty.buffer.AbstractByteBufAllocator.toLeakAwareBuffer(",
        "io.netty.buffer.AdvancedLeakAwareByteBuf.recordLeakNonRefCountingOperation("
};


//StringUtil
package io.netty.util.internal;
/**
 * String utility class.
 */
public final class StringUtil {

    public static final String EMPTY_STRING = "";
    public static final String NEWLINE = SystemPropertyUtil.get("line.separator", "\n");

    public static final char DOUBLE_QUOTE = '\"';
    public static final char COMMA = ',';
    public static final char LINE_FEED = '\n';
    public static final char CARRIAGE_RETURN = '\r';
    public static final char TAB = '\t';
    ...
}

//泄漏资源LeakEntryEntry
 private static final class LeakEntry {
    static final LeakEntry INSTANCE = new LeakEntry();//内部实例
    private static final int HASH = System.identityHashCode(INSTANCE);//实例hash值

    private LeakEntry() {
    }

    @Override
    public int hashCode() {
        return HASH;
    }
    @Override
    public boolean equals(Object obj) {
        return obj == this;
    }
}

从上面可以看出,默认资源泄漏DefaultResourceLeak,构造过程为,首先将资源添加到引用队列,如果探测等级大于ADVANCED,则创建记录,然后添加资源泄漏对象到资源泄漏探测器的激活对象Map中。

再来看DefaultResourceLeak的记录和关闭资源操作:


@Override
public void record() {
    record0(null, 3);
}

@Override
public void record(Object hint) {
    record0(hint, 3);
}

private void record0(Object hint, int recordsToSkip) {
    if (creationRecord != null) {
        //根据资源泄漏线索,创建泄漏线索信息
        String value = newRecord(hint, recordsToSkip);

        synchronized (lastRecords) {
            int size = lastRecords.size();
            if (size == 0 || !lastRecords.getLast().equals(value)) {
	        //如果泄漏线索信息集为空,或者与上次记录不同,则添加泄漏信息到泄漏记录集
                lastRecords.add(value);
            }
            if (size > MAX_RECORDS) {
	        //如果记录超过最大记录数,则从对头移除记录信息
                lastRecords.removeFirst();
                ++removedRecords;//更新移除记录计数器
            }
        }
    }
}

从上面可以看出,记录资源泄漏,首先根据资源泄漏线索,创建泄漏线索信息,
如果泄漏线索信息集为空,或者与上次记录不同,则添加泄漏信息到泄漏记录集,
如果记录超过最大记录数,则从对头移除记录信息。

再来看关闭资源

 @Override
 public boolean close() {
     // Use the ConcurrentMap remove method, which avoids allocating an iterator.
     //从资源泄漏探测器移除资源泄漏对象
     return allLeaks.remove(this, LeakEntry.INSTANCE);
 }

 @Override
 public boolean close(T trackedObject) {
     // Ensure that the object that was tracked is the same as the one that was passed to close(...).
     assert trackedHash == System.identityHashCode(trackedObject);

     // We need to actually do the null check of the trackedObject after we close the leak because otherwise
     // we may get false-positives reported by the ResourceLeakDetector. This can happen as the JIT / GC may
     // be able to figure out that we do not need the trackedObject anymore and so already enqueue it for
     // collection before we actually get a chance to close the enclosing ResourceLeak.
     return close() && trackedObject != null;
 }

从上面来看,关闭资源探测对象,就是从资源泄漏探测器移除资源泄漏对象。

//资源泄漏对象信息
@Override
 public String toString() {
     if (creationRecord == null) {
         return EMPTY_STRING;
     }

     final Object[] array;
     final int removedRecords;
     synchronized (lastRecords) {
         array = lastRecords.toArray();
         removedRecords = this.removedRecords;
     }

     StringBuilder buf = new StringBuilder(16384).append(NEWLINE);
     if (removedRecords > 0) {
        //报告,由于泄漏记录数限制,丢弃的记录数
         buf.append("WARNING: ")
         .append(removedRecords)
         .append(" leak records were discarded because the leak record count is limited to ")
         .append(MAX_RECORDS)
         .append(". Use system property ")
         .append(PROP_MAX_RECORDS)
         .append(" to increase the limit.")
         .append(NEWLINE);
     }
     buf.append("Recent access records: ")
     .append(array.length)
     .append(NEWLINE);
    //报告,记录的资源泄漏信息
     if (array.length > 0) {
         for (int i = array.length - 1; i >= 0; i --) {
             buf.append('#')
                .append(i + 1)
                .append(':')
                .append(NEWLINE)
                .append(array[i]);
         }
     }
     //报告资源泄漏创建信息
     buf.append("Created at:")
        .append(NEWLINE)
        .append(creationRecord);

     buf.setLength(buf.length() - NEWLINE.length());
     return buf.toString();
 }
 

从上面来看,报告资源泄漏信息,主要是报告由于泄漏记录数限制,丢弃的记录数,记录的资源泄漏信息,
资源泄漏创建信息。

回到资源泄漏探测器,根据资源,创建资源泄漏追踪器:

/
**
 * Creates a new {@link ResourceLeakTracker} which is expected to be closed via
 * {@link ResourceLeakTracker#close(Object)} when the related resource is deallocated.
 *创建一个资源泄漏ResourceLeakTracker,当相关资源释放时,希望通过ResourceLeakTracker#close(Object)关闭对象
 * @return the {@link ResourceLeakTracker} or {@code null}
 */
public final ResourceLeakTracker<T> track(T obj) {
    return track0(obj);
}

//追踪资源泄漏对象线索
private DefaultResourceLeak track0(T obj) {
    Level level = ResourceLeakDetector.level;
    if (level == Level.DISABLED) {
        return null;
    }
    if (level.ordinal() < Level.PARANOID.ordinal()) {
        if ((PlatformDependent.threadLocalRandom().nextInt(samplingInterval)) == 0) {
	    //根据探测等级,报告探测结果
            reportLeak(level);
	    //创建资源泄漏对象
            return new DefaultResourceLeak(obj);
        } else {
            return null;
        }
    } else {
        reportLeak(level);
        return new DefaultResourceLeak(obj);
    }
}


来看根据探测等级,报告探测结果
//根据探测等级,报告探测结果  
reportLeak(level);



private void reportLeak(Level level) {
    if (!logger.isErrorEnabled()) {
        //如果日志Error级别没有开启,则将资源探测对象的引用队列中,poll探测对象,并关闭
        for (;;) {
            @SuppressWarnings("unchecked")
            DefaultResourceLeak ref = (DefaultResourceLeak) refQueue.poll();
            if (ref == null) {
                break;
            }
            ref.close();
        }
        return;
    }

    // Detect and report previous leaks. 报告内存泄漏请求
    for (;;) {
        @SuppressWarnings("unchecked")
	//
        DefaultResourceLeak ref = (DefaultResourceLeak) refQueue.poll();
        if (ref == null) {
            break;
        }
        //清除引用
        ref.clear();

        if (!ref.close()) {
	   //如果资源泄漏对象没关闭,则跳出当前循环
            continue;
        }
        //获取资源泄漏探测信息
        String records = ref.toString();
	//记录资源泄漏信息
        if (reportedLeaks.putIfAbsent(records, Boolean.TRUE) == null) {
            if (records.isEmpty()) {
	        //资源泄漏记录为空,则报告不可追踪
                reportUntracedLeak(resourceType);
            } else {
	        //报告资源泄漏信息
                reportTracedLeak(resourceType, records);
            }
        }
    }
}

从上面可以看出,资源泄漏探测器,追踪资源泄漏探测信息,在采样点到达时,首先从资源泄漏引用队列,获取资源泄漏对象对象,关闭资源泄漏对象,并将探测结果添加到探测器的资源泄漏信息Map中,然后报告资源泄漏探测信息,最后创建资源探测对象。


来看需要关注的几点:
1.
//清除引用
//Reference
public abstract class Reference<T> {
    private T referent;         /* Treated specially by GC */

    ReferenceQueue<? super T> queue;

    Reference next;
    transient private Reference<T> discovered;  /* used by VM */


    /* Object used to synchronize with the garbage collector.  The collector
     * must acquire this lock at the beginning of each collection cycle.  It is
     * therefore critical that any code holding this lock complete as quickly
     * as possible, allocate no new objects, and avoid calling user code.
     */
    static private class Lock { };
    private static Lock lock = new Lock();


    /* List of References waiting to be enqueued.  The collector adds
     * References to this list, while the Reference-handler thread removes
     * them.  This list is protected by the above lock object.
     */
    private static Reference pending = null;
        
    /**
      * Clears this reference object.  Invoking this method will not cause this
      * object to be enqueued.
      * 清除对象引用
      * <p> This method is invoked only by Java code; when the garbage collector
      * clears references it does so directly, without invoking this method.
      */
     public void clear() {
         this.referent = null;
     }
    ...
}

2.
/**
 * This method is called when a traced leak is detected. It can be overridden for tracking how many times leaks
 * have been detected.
 报告资源泄漏信息
 */
protected void reportTracedLeak(String resourceType, String records) {
    logger.error(
            "LEAK: {}.release() was not called before it's garbage-collected. " +
            "See http://netty.io/wiki/reference-counted-objects.html for more information.{}",
            resourceType, records);
}

3.
/**
 * This method is called when an untraced leak is detected. It can be overridden for tracking how many times leaks
 * have been detected.
报告不可追踪
 */
protected void reportUntracedLeak(String resourceType) {
    logger.error("LEAK: {}.release() was not called before it's garbage-collected. " +
            "Enable advanced leak reporting to find out where the leak occurred. " +
            "To enable advanced leak reporting, " +
            "specify the JVM option '-D{}={}' or call {}.setLevel() " +
            "See http://netty.io/wiki/reference-counted-objects.html for more information.",
            resourceType, PROP_LEVEL, Level.ADVANCED.name().toLowerCase(), simpleClassName(this));
}


总结:
默认的资源泄漏探测器工厂创建的资源泄漏探测器为ResourceLeakDetector。

资源泄漏探测器,探测等级有四种,关闭DISABLED,SIMPLE简单,高级ADVANCED,终极PARANOID,SIMPLE开启简单的采样资源泄漏探测,仅仅已少量的负载为代价报告是否为泄漏对象;ADVANCED开启高级采样泄漏探测,将会以高负载为代价,报告最近泄漏对象访问的地方;
PARANOID开启终极采样泄漏探测,将会以高级负载为代价,报告最近泄漏对象访问的地方(仅仅测试);开启资源探测的情况下,默认等级为SIMPLE。资源探测器内部有一个探测等级和采样间隔,资源类型,泄漏报告Map( ConcurrentMap<String, Boolean>),激活资源集合ConcurrentMap<DefaultResourceLeak, LeakEntry>。

资源泄漏探测器构造,主要初始化资源类型名及探测间隔。

资源泄漏追踪ResourceLeakTracker,主要定义了记录当前调用者栈追踪和额外的主观信息方法,
以便资源泄漏探测器可以告诉,泄漏资源最近访问的地方;关闭泄漏资源方法,以便资源泄漏探测器不在警告泄漏资源。

默认资源泄漏DefaultResourceLeak,构造过程为,首先将资源添加到引用队列,如果探测等级大于ADVANCED,则创建记录,然后添加资源泄漏对象到资源泄漏探测器的激活对象Map中。

记录资源泄漏,首先根据资源泄漏线索,创建泄漏线索信息,如果泄漏线索信息集为空,或者与上次记录不同,则添加泄漏信息到泄漏记录集,如果记录超过最大记录数,则从对头移除记录信息。

关闭资源探测对象,就是从资源泄漏探测器移除资源泄漏对象。

报告资源泄漏信息,主要是报告由于泄漏记录数限制,丢弃的记录数,记录的资源泄漏信息,
资源泄漏创建信息。

资源泄漏探测器,追踪资源泄漏探测信息,在采样点到达时,首先从资源泄漏引用队列,获取资源泄漏对象对象,关闭资源泄漏对象,并将探测结果添加到探测器的资源泄漏信息Map中,然后报告资源泄漏探测信息,最后创建资源探测对象。


附:

//PhantomReference
package java.lang.ref;


/**
 * Phantom reference objects, which are enqueued after the collector
 * determines that their referents may otherwise be reclaimed.  Phantom
 * references are most often used for scheduling pre-mortem cleanup actions in
 * a more flexible way than is possible with the Java finalization mechanism.
 *
 * <p> If the garbage collector determines at a certain point in time that the
 * referent of a phantom reference is <a
 * href="package-summary.html#reachability">phantom reachable</a>, then at that
 * time or at some later time it will enqueue the reference.
 *
 * <p> In order to ensure that a reclaimable object remains so, the referent of
 * a phantom reference may not be retrieved: The <code>get</code> method of a
 * phantom reference always returns <code>null</code>.
 *
 * <p> Unlike soft and weak references, phantom references are not
 * automatically cleared by the garbage collector as they are enqueued.  An
 * object that is reachable via phantom references will remain so until all
 * such references are cleared or themselves become unreachable.
 *
 * @author   Mark Reinhold
 * @since    1.2
 */

public class PhantomReference<T> extends Reference<T> {

    /**
     * Returns this reference object's referent.  Because the referent of a
     * phantom reference is always inaccessible, this method always returns
     * <code>null</code>.
     *
     * @return  <code>null</code>
     */
    public T get() {
        return null;
    }

    /**
     * Creates a new phantom reference that refers to the given object and
     * is registered with the given queue.
     *
     * <p> It is possible to create a phantom reference with a <tt>null</tt>
     * queue, but such a reference is completely useless: Its <tt>get</tt>
     * method will always return null and, since it does not have a queue, it
     * will never be enqueued.
     *
     * @param referent the object the new phantom reference will refer to
     * @param q the queue with which the reference is to be registered,
     *          or <tt>null</tt> if registration is not required
     */
    public PhantomReference(T referent, ReferenceQueue<? super T> q) {
        super(referent, q);
    }

}


//Reference
/**
 * Abstract base class for reference objects.  This class defines the
 * operations common to all reference objects.  Because reference objects are
 * implemented in close cooperation with the garbage collector, this class may
 * not be subclassed directly.
 *
 * @author   Mark Reinhold
 * @since    1.2
 */

public abstract class Reference<T> {

    /* A Reference instance is in one of four possible internal states:
     *
     *     Active: Subject to special treatment by the garbage collector.  Some
     *     time after the collector detects that the reachability of the
     *     referent has changed to the appropriate state, it changes the
     *     instance's state to either Pending or Inactive, depending upon
     *     whether or not the instance was registered with a queue when it was
     *     created.  In the former case it also adds the instance to the
     *     pending-Reference list.  Newly-created instances are Active.
     *
     *     Pending: An element of the pending-Reference list, waiting to be
     *     enqueued by the Reference-handler thread.  Unregistered instances
     *     are never in this state.
     *
     *     Enqueued: An element of the queue with which the instance was
     *     registered when it was created.  When an instance is removed from
     *     its ReferenceQueue, it is made Inactive.  Unregistered instances are
     *     never in this state.
     *
     *     Inactive: Nothing more to do.  Once an instance becomes Inactive its
     *     state will never change again.
     *
     * The state is encoded in the queue and next fields as follows:
     *
     *     Active: queue = ReferenceQueue with which instance is registered, or
     *     ReferenceQueue.NULL if it was not registered with a queue; next =
     *     null.
     *
     *     Pending: queue = ReferenceQueue with which instance is registered;
     *     next = Following instance in queue, or this if at end of list.
     *
     *     Enqueued: queue = ReferenceQueue.ENQUEUED; next = Following instance
     *     in queue, or this if at end of list.
     *
     *     Inactive: queue = ReferenceQueue.NULL; next = this.
     *
     * With this scheme the collector need only examine the next field in order
     * to determine whether a Reference instance requires special treatment: If
     * the next field is null then the instance is active; if it is non-null,
     * then the collector should treat the instance normally.
     *
     * To ensure that concurrent collector can discover active Reference
     * objects without interfering with application threads that may apply
     * the enqueue() method to those objects, collectors should link
     * discovered objects through the discovered field.
     */

    private T referent;         /* Treated specially by GC */

    ReferenceQueue<? super T> queue;

    Reference next;
    transient private Reference<T> discovered;  /* used by VM */


    /* Object used to synchronize with the garbage collector.  The collector
     * must acquire this lock at the beginning of each collection cycle.  It is
     * therefore critical that any code holding this lock complete as quickly
     * as possible, allocate no new objects, and avoid calling user code.
     */
    static private class Lock { };
    private static Lock lock = new Lock();


    /* List of References waiting to be enqueued.  The collector adds
     * References to this list, while the Reference-handler thread removes
     * them.  This list is protected by the above lock object.
     */
    private static Reference pending = null;

    /* High-priority thread to enqueue pending References
     */
    private static class ReferenceHandler extends Thread {

        ReferenceHandler(ThreadGroup g, String name) {
            super(g, name);
        }

        public void run() {
            for (;;) {

                Reference r;
                synchronized (lock) {
                    if (pending != null) {
                        r = pending;
                        Reference rn = r.next;
                        pending = (rn == r) ? null : rn;
                        r.next = r;
                    } else {
                        try {
                            lock.wait();
                        } catch (InterruptedException x) { }
                        continue;
                    }
                }

                // Fast path for cleaners
                if (r instanceof Cleaner) {
                    ((Cleaner)r).clean();
                    continue;
                }

                ReferenceQueue q = r.queue;
                if (q != ReferenceQueue.NULL) q.enqueue(r);
            }
        }
    }

    static {
        ThreadGroup tg = Thread.currentThread().getThreadGroup();
        for (ThreadGroup tgn = tg;
             tgn != null;
             tg = tgn, tgn = tg.getParent());
        Thread handler = new ReferenceHandler(tg, "Reference Handler");
        /* If there were a special system-only priority greater than
         * MAX_PRIORITY, it would be used here
         */
        handler.setPriority(Thread.MAX_PRIORITY);
        handler.setDaemon(true);
        handler.start();
    }


    /* -- Referent accessor and setters -- */

    /**
     * Returns this reference object's referent.  If this reference object has
     * been cleared, either by the program or by the garbage collector, then
     * this method returns <code>null</code>.
     *
     * @return   The object to which this reference refers, or
     *           <code>null</code> if this reference object has been cleared
     */
    public T get() {
        return this.referent;
    }

    /**
     * Clears this reference object.  Invoking this method will not cause this
     * object to be enqueued.
     *
     * <p> This method is invoked only by Java code; when the garbage collector
     * clears references it does so directly, without invoking this method.
     */
    public void clear() {
        this.referent = null;
    }


    /* -- Queue operations -- */

    /**
     * Tells whether or not this reference object has been enqueued, either by
     * the program or by the garbage collector.  If this reference object was
     * not registered with a queue when it was created, then this method will
     * always return <code>false</code>.
     *
     * @return   <code>true</code> if and only if this reference object has
     *           been enqueued
     */
    public boolean isEnqueued() {
        /* In terms of the internal states, this predicate actually tests
           whether the instance is either Pending or Enqueued */
        synchronized (this) {
            return (this.queue != ReferenceQueue.NULL) && (this.next != null);
        }
    }

    /**
     * Adds this reference object to the queue with which it is registered,
     * if any.
     *
     * <p> This method is invoked only by Java code; when the garbage collector
     * enqueues references it does so directly, without invoking this method.
     *
     * @return   <code>true</code> if this reference object was successfully
     *           enqueued; <code>false</code> if it was already enqueued or if
     *           it was not registered with a queue when it was created
     */
    public boolean enqueue() {
        return this.queue.enqueue(this);
    }


    /* -- Constructors -- */

    Reference(T referent) {
        this(referent, null);
    }

    Reference(T referent, ReferenceQueue<? super T> queue) {
        this.referent = referent;
        this.queue = (queue == null) ? ReferenceQueue.NULL : queue;
    }

}

猜你喜欢

转载自donald-draper.iteye.com/blog/2393940