以下是在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");
}
}
答案 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
。