前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >WeakHashMap垃圾回收原理

WeakHashMap垃圾回收原理

作者头像
涤生
发布2018-08-14 14:36:09
3820
发布2018-08-14 14:36:09
举报
文章被收录于专栏:涤生的博客涤生的博客

简书 涤生。 转载请注明原创出处,谢谢!

介绍

WeakHashMap自然联想到的是HashMap。确实,WeakHashMap与HashMap一样是个散列表,存储内容也是键值对。与HashMap类似的功能就不展开了,本文重点关注在WeakHashMap是如何做到回收数据?

垃圾回收原理

谈WeakHashMap回收原理得从WeakReference(弱引用)说起。大家都知道GC回收对象前提是,从根集出发的引用中没有有效引用指向该对象,则该对象就可以被回收,这里的有效引用并不包含WeakReference,虽然弱引用可以用来访问对象,但进行垃圾回收时弱引用并不会被考虑在内,仅有弱引用指向的对象仍然会被GC回收。 那WeakHashMap是如何跟WeakReference关联起来的呢? 我们一起看看实现的code吧。

代码语言:javascript
复制
/**
     * The entries in this hash table extend WeakReference, using its main ref
     * field as the key.
     */
    private static class Entry<K,V> extends WeakReference<Object> implements Map.Entry<K,V> {
        V value;
        int hash;
        Entry<K,V> next;

        /**
         * Creates new entry.
         */
        Entry(Object key, V value,
              ReferenceQueue<Object> queue,
              int hash, Entry<K,V> next) {
            super(key, queue);
            this.value = value;
            this.hash  = hash;
            this.next  = next;
        }

大家都知道HashMap实现里面有个Entry数组,WeakHashMap也一样也有一个Entry数组,但是此Entry与彼Entry有些不一样。WeakHashMap的Entry是继承WeakReference,这样一来,整个Entry就是一个WeakReference,再来看看Entry的构造方法,调用了super(key, queue),也就是调用了这个构造方法

代码语言:javascript
复制
public class WeakReference<T> extends Reference<T> {

    /**
     * Creates a new weak reference that refers to the given object.  The new
     * reference is not registered with any queue.
     *
     * @param referent object the new weak reference will refer to
     */
    public WeakReference(T referent) {
        super(referent);
    }

    /**
     * Creates a new weak reference that refers to the given object and is
     * registered with the given queue.
     *
     * @param referent object the new weak 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 WeakReference(T referent, ReferenceQueue<? super T> q) {
        super(referent, q);
    }

}

有两个参数,一个key,一个是queue,这个key就是WeakHashMap中存储的key值,这个queue是WeakHashMap中创建的ReferenceQueue。

代码语言:javascript
复制
/**
     * Reference queue for cleared WeakEntries
     */
    private final ReferenceQueue<Object> queue = new ReferenceQueue<>();

那这个ReferenceQueue是干嘛的呢?了解GC的朋友可能知道,当GC某个对象时,如果有此对象上还有弱引用与其关联,会将WeakReference对象与Reference类的pending引用关联起来,然后由Reference Handler线程将该插入ReferenceQueue队列。 也就是说当Entry中的key被GC时,会将Entry放入到ReferenceQueue中,WeakHashMap就能个通过ReferenceQueue中的Entry了解到哪些key已经被GC,或者即将马上被GC,起到了通知的作用。

了解了以上信息后,我们再看下面这段代码:

代码语言:javascript
复制
/**
     * Expunges stale entries from the table.
     */
    private void expungeStaleEntries() {
        for (Object x; (x = queue.poll()) != null; ) {
            synchronized (queue) {
                @SuppressWarnings("unchecked")
                    Entry<K,V> e = (Entry<K,V>) x;
                int i = indexFor(e.hash, table.length);

                Entry<K,V> prev = table[i];
                Entry<K,V> p = prev;
                while (p != null) {
                    Entry<K,V> next = p.next;
                    if (p == e) {
                        if (prev == e)
                            table[i] = next;
                        else
                            prev.next = next;
                        // Must not null out e.next;
                        // stale entries may be in use by a HashIterator
                        e.value = null; // Help GC
                        size--;
                        break;
                    }
                    prev = p;
                    p = next;
                }
            }
        }
    }

这段代码就是WeakHashMap用来处理ReferenceQueue中被GC的key所关联的Entry相关数据,通过从queue中poll出相关的Entry,然后去WeakHashMap的entry数组中找到索引,然后从对应的链中去掉相关的Entry,最后将value赋值为空(Help GC),到这里就完成了相关数据的清理。 但是谁来触发expungeStaleEntries方法呢?有多个方法都可以触发,如put、get、remove、size等方法都能够触发相关的逻辑。

误区

是不是使用了WeakHashMap就一定没有问题了呢?当然不是,如果没有触发expungeStaleEntries这个方法依然会导致内存泄漏,比如初始化好WeakHashMap中相关数据后,一直不调用put、get、remove、size等相关方法,也是不能够正常回收的。

总结

了解了WeakHashMap原理之后,使用起来是不是更加得心应手了呢。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-01-19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 涤生的博客 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 介绍
  • 垃圾回收原理
  • 误区
  • 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档