一旦取消引用,弱hashmap是否会释放内存?

时间:2016-12-01 11:34:49

标签: java hashmap

以下是在WeakHashMap中放置一些值然后从地图中删除它们的代码段。它如何处理分配的内存?

import java.util.*;
public class WeakHashMap_Main {
    private static Map map;

    public static void main(String args[]) {
        map = new WeakHashMap();
        map.put(new String("ABC"), "XYZ");
        map.put(new String("DEF"), "PQR");

        map.remove("ABC");
        map.remove("DEF");
    }
}

4 个答案:

答案 0 :(得分:1)

WeakHashMap 使用的内存可能在以下场景中被释放:

public static void main(String args[]) {
    Map<String, String> map = new WeakHashMap<>();
    String abc = "ABC";
    String def = "DEF";
    map.put(abc, "XYZ");
    map.put(def, "PQR");
    System.out.println(map.size());  // Guaranteed to be 2.

    // Note: DO NOT remove the map entries!
    // map.remove("ABC");
    // map.remove("DEF");

    // Allow the objects to be reclaimed
    abc = null;
    def = null;

    // Do loads of memory-hungry operations here...
    ...

    System.out.println(map.size());  // MAY POSSIBLY be 0 or 1. Or still 2.
}

这完全取决于垃圾收集器决定做什么(如果有的话)。

这里的重点是,在添加两个条目后我们还没有触及地图。

答案 1 :(得分:1)

Java docs(jdk1.8.0_71)说,

  

WeakHashMap中的条目如果是关键字,将自动删除   不再是一般用途。更准确地说,存在一个   给定密钥的映射不会阻止密钥被丢弃   由垃圾收集器。

这清楚地表明,当key被废弃后,其Entry<K, V>也将从Map中删除。

现在,让我们一起来看一看,并检查删除key后会发生什么。 remove(Object o)方法的代码段如下所示:

public V remove(Object key) {
        Object k = maskNull(key);
        int h = hash(k);
        Entry<K,V>[] tab = getTable();
        int i = indexFor(h, tab.length);
        Entry<K,V> prev = tab[i];
        Entry<K,V> e = prev;

        while (e != null) {
            Entry<K,V> next = e.next;
            if (h == e.hash && eq(k, e.get())) {
                modCount++;
                size--;
                if (prev == e)
                    tab[i] = next;
                else
                    prev.next = next;
                return e.value;
            }
            prev = e;
            e = next;
        }

        return null;
    }

可以观察到,该方法首先通过调用Entry<K, V>方法获取getTable()数组。每次调用getTable()时,都会调用另一个方法expungeStaleEntries()。此特定方法将使用保留已清除ReferenceQueue<Object>的{​​{1}},并从WeakEntries中删除陈旧条目。该方法的代码片段如下所示:

Entry<K, V>[] table

通过代码片段可以看出,每个条目都被添加到/** * 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中(queue操作期间的调用构造函数为如下所示:

put(K, V)

)并且在清除操作期间从Entry<K,V> e = tab[i]; tab[i] = new Entry<>(k, value, queue, h, e); 检索并删除相同的条目。此已移除的queue的值设置为空Entry<K, V>,稍后将 GC&#39; d 。是的,它对 GC 没有任何控制权。这就是e.value = null有助于使用密钥丢弃映射值的方法。

答案 2 :(得分:0)

内存在创建时分配给对象。任何数量的其他对象都可以引用该对象,因此也可以引用其分配的内存。

垃圾收集器是JVM的一个元素,它确定哪些对象仍然被引用(以及哪些对象是弱引用的)。它将所有不再引用的内存放回堆中,并且可以再次使用。在任何条件下,如果内存足够低等,它也会将仅由弱引用引用的内存放回堆中,并使用弱引用执行其魔法,以便程序可以告诉它们不再有效。

因此,如果您在WeakHashMap中放置对象的引用,然后将它们取出,并且那些是对这些对象的唯一引用,那么这些对象将不再被引用并且可用于垃圾收集。

答案 3 :(得分:0)

课程WeakHasMap适用于WeakReferences的{​​{1}}。普通keys与密钥的HashMap一起使用。

垃圾收集由JVM自行调节。我们只能通过调用StrongReferences来尝试影响JVM来执行垃圾收集。 System.gc()可防止密钥被垃圾回收。 HashMap不会阻止密钥被垃圾回收。如果存储在正常WeakHashMap中的密钥没有留下StrongReference,则它将保留在HashMap中,直到明确删除为止,之后密钥对象将符合条件垃圾收集。但是如果没有任何HashMap的密钥存储在StrongReference中,则它将符合垃圾收集的条件。一旦执行了垃圾收集的循环,密钥将被垃圾收集,然后该密钥对象上的WeakHashMap方法将返回contains