Lucene源码解析--Lucene中的CloseableThreadLocal类

本文深入探讨了Java中ThreadLocal类的内存管理问题,特别是ThreadLocal实例在不再被引用时如何长时间占用内存。通过引入CloseableThreadLocal解决此问题,并解释了Java中的四种引用类型(StrongReference、SoftReference、WeakReference、PhantomReference)及其作用。文章还详细阐述了如何利用WeakReference和ReferenceQueue进行内存清理,以及如何避免由于对象引用导致的无限GC循环。
Java的ThreadLocal类有一个严重的瑕疵那就是即便在ThreadLocal 实例本身不在被引用的情况下,其中存储的东西也需要相当长的时间才能被解除引用。原因是所有的ThreadLocal 实例共享一个map,而该map只会在指定的时间段内清除过期的条目。

CloseableThreadLocal通过接收WeakReference类型的值并且保持对每个存储值一个硬应用,当调用close()方法的时候会清楚所有的引用,这样GC就可以回收所占用的内存空间。

Java 中一共有 4 种类型的引用 : StrongReference、 SoftReference、 WeakReference 以及 PhantomReference。

一:Strong Reference
StrongReference 是 Java 的默认引用实现,  它会尽可能长时间的存活于 JVM 内, 当没有任何对象指向它时 GC 执行后将会被回收
    public static void main(String[] args) {
        Object bject = new Object();

        // 通过赋值创建 StrongReference
        Object referent = object;

        System.out.println(referent == object);
        /************** true **********************/

        bject = null;
        System.gc();

        // StrongReference 在 GC 后不会被回收

        System.out.println(null == referent);
        /************** false **********************/
    }

二:WeakReference & WeakHashMap
WeakReference, 顾名思义,  是一个弱引用,  当所引用的对象在 JVM 内不再有强引用时, GC 后 weak reference 将会被自动回收
    public static void main(String[] args) {
        Object bject = new Object();

        // 创建 WeakReference
        WeakReference referent = new WeakReference(object);

        bject = null;
        System.gc();

        //一旦没有指向 referent 的强引用, WeakReference 在 GC 后会被自动回收

        System.out.println(null == referent.get());
        /************** false **********************/
    }

WeakHashMap 使用 WeakReference 作为 key, 一旦没有指向 key 的强引用, WeakHashMap 在 GC 后将自动删除相关的 entry

public static void main(String[] args) throws Exception {
        Map weakHashMap = new WeakHashMap();
        Object key = new Object();
        Object value = new Object();
        weakHashMap.put(key, value);

        System.out.println(weakHashMap.containsValue(value));

        key = null;
        System.gc();

        /**
         * 等待无效 entries 进入 ReferenceQueue 以便下一次调用 getTable 时被清理
         */
        Thread.sleep(1000);

        /**
         * 一旦没有指向 key 的强引用, WeakHashMap 在 GC 后将自动删除相关的 entry
         */
        System.out.println(weakHashMap.containsValue(value));
    }

三:SoftReference
SoftReference 于 WeakReference 的特性基本一致, 最大的区别在于 SoftReference 会尽可能长的保留引用直到 JVM 内存不足时才会被回收(虚拟机保证), 这一特性使得 SoftReference 非常适合缓存应用

四:PhantomReference
Phantom Reference(幽灵引用) 与 WeakReference 和 SoftReference 有很大的不同,  因为它的 get() 方法永远返回 null, 这也正是它名字的由来。PhantomReference 唯一的用处就是跟踪 referent  何时被 enqueue 到 ReferenceQueue 中.

五:RererenceQueue
当一个 WeakReference 开始返回 null 时, 它所指向的对象已经准备被回收, 这时可以做一些合适的清理工作.   将一个 ReferenceQueue 传给一个 Reference 的构造函数, 当对象被回收时, 虚拟机会自动将这个对象插入到 ReferenceQueue 中, WeakHashMap 就是利用 ReferenceQueue 来清除 key 已经没有强引用的 entries.
    public static void main(String[] args) throws Exception {
        Object bject = new Object();
        ReferenceQueue referenceQueue = new ReferenceQueue();
        WeakReference weakReference = new WeakReference(object,
                referenceQueue);

        System.out.println(weakReference.isEnqueued());
        /************** false **************/
        Reference extends Object> polled = referenceQueue.poll();
        System.out.println(null == polled);
        /************** true **************/
        // 取消引用
        bject = null;
        System.gc();

        System.out.println(weakReference.isEnqueued());
        /************** true **************/
        Reference extends Object> removed = referenceQueue.remove();
        System.out.println(null == removed);
        /************** false **************/
    }



Object 的 finalize 方法, 将在 gc 执行前被调用, 如果某个对象重载了 finalize 方法并故意在方法内创建本身的强引用,  这将导致这一轮的 GC 无法回收这个对象并有可能引 起任意次 GC, 最后的结果就是明明 JVM 内有很多 Garbage 却 OutOfMemory, 使用 PhantomReference 就可以避免这个问题, 因为 PhantomReference 是在 finalize 方法执行后回收的,也就意味着此时已经不可能拿到原来的引用,  也就不会出现上述问题。

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/28624388/viewspace-763745/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/28624388/viewspace-763745/

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值