4

我正在理解 WeakhashMap 的概念。字符串文字和字符串对象让人难以理解。

以下是代码:

package com.lnt.StringBuf;

import java.util.HashMap;
import java.util.Map;
import java.util.WeakHashMap;

public class Test1 {
    public static void main(String[] args) {

        Map w = new WeakHashMap();
        Map h = new HashMap<>();

        String hkey = new String("hashkey");
        String wkey = new String("weakkey");
    /*  String hkey = "hashkey";
        String wkey = "weakkey";*/

        h.put(hkey, 1);
        w.put(wkey, 1);

        System.gc();

        System.out.println("Before");
        System.out.println("hashmap size: " + h.size());
        System.out.println("weakmap size: " + w.size());
        System.out.println("Hashmap value: " + h.get("hashkey") + "\t"
                + "weakmap value: " + w.get("weakkey"));

        hkey = null;
        wkey = null;

        System.gc();
        System.out.println(hkey+" "+wkey);

        System.out.println("After");
        System.out.println("hashmap size: " + h.size());
        System.out.println("weakmap size: " + w.size());
        System.out.println("Hashmap value: " + h.get("hashkey") + "\t"
                + "weakmap value: " + w.get("weakkey"));

        System.out.println(h.entrySet());
        System.out.println(w.entrySet());

    }

}

输出是:

Before
hashmap size: 1
weakmap size: 1
Hashmap value: 1    weakmap value: 1
null null
After
hashmap size: 1
weakmap size: 0
Hashmap value: 1    weakmap value: null
[hashkey=1]
[]

但是当 String hkey = new String("hashkey"); 字符串 wkey = new String("weakkey");

替换为以下代码,输出更改。

String hkey = "hashkey";
String wkey = "weakkey";

输出是:

Before
hashmap size: 1
weakmap size: 1
Hashmap value: 1    weakmap value: 1
null null
After
hashmap size: 1
weakmap size: 1
Hashmap value: 1    weakmap value: 1
[hashkey=1]
[weakkey=1]

问题:在 WeakHashMap 中以不同的方式使字符串字面量和字符串对象“空”产生影响。是什么原因?

4

3 回答 3

8

字符串字面量是实习的,这基本上意味着有一个缓存,通常称为字符串池。所以字符串文字总是被强引用——这使得它们不适合用作弱结构中的键,例如WeakReferenceWeakHashMap

autoboxed ints 也是如此:还为[-128, 127] 范围内的值Integer保留Integer对象缓存。int所以你也不应该int在弱结构中使用 for 键。

但是,您可以通过在插入条目时创建一个新对象来解决这些问题,例如,在以下示例中,“a”条目最终将从地图中删除,但“b”条目将永远保留在那里,即实际上是内存泄漏:

WeakHashMap<String, Object> map = new WeakHashMap<>();
map.add(new String("a"), new Object());
map.add("b", new Object());

相同的示例对整数有效:

WeakHashMap<Integer, Object> map = new WeakHashMap<>();
map.add(new Integer(56), new Object());
map.add(57, new Object());

这里 57 的条目将永远保留在那里,因为Integer' 缓存,但 56 条目可以被垃圾收集器删除。

Boolean有缓存,但当然只适用于 2 个值。whereInteger有 256 个潜在危险值,String实际上有无限的可能是危险的发生 - 你只需要使用文字(或使用String.intern())来创建它们。也可能存在其他危险类别。

于 2015-02-16T09:17:12.773 回答
2

在 WeakHashMap 中,使字符串字面量和字符串对象为“空”以不同的方式产生影响。是什么原因?

首先,你不能制作一个对象null。你可以做一个变量引用null或者引用一个对象,但是做一个对象null并不是一个存在的概念。

WeakHashMap各州的 javadoc

a 中的条目WeakHashMap将在其密钥不再正常使用时自动删除。更准确地说,给定键的映射的存在不会阻止该键被垃圾收集器丢弃,也就是说,使其可最终化、最终化,然后被回收。

在运行时,JVM 为它在加载类时看到String的每个字面量创建一个对象。String在加载它们的对象被 GC 之前,这些对象不能被ClassLoaderGC,无论它们是否在WeakHashMap.

这类似于做

String wkey =  new String("weak");
String other = wkey;

由于您在其他地方拥有对该对象的可访问引用,因此即使在集合中使用它也不能被 GC 处理。

另请注意,System.gc()不保证垃圾收集会运行。使用它时要注意这一点,以免误解结果。

于 2014-05-27T04:56:46.847 回答
0

如果用作键,则字符串不适合 WeakHashMap。这是因为,当创建 String 对象时,JVM 也会在 String 池中创建该对象。即使您取消了引用,它们也可能在字符串池中保持强引用。

Map<String, String> stringWeakHashMap = new WeakHashMap<String, String>();
String str1 = "Key 1";
String str2 = "Key 2";

stringWeakHashMap.put(str1, "Value 1");
stringWeakHashMap.put(str2, "Value 2");
str1 = null;

System.gc();
System.out.println("Weak Hash Map :" + stringWeakHashMap.toString());

运行上述代码后,生成的输出为

弱哈希映射:{Key 2=Value 2, Key 1=Value 1}

于 2015-01-13T14:22:05.307 回答