弱引用哈希映射(weakhashmap)在处理字符串字面量和字符串对象时的行为

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 = "hashkey"; String wkey = "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中,将字符串字面量和字符串对象设置为“null”会产生不同的影响。原因是什么?

3个回答

8

字符串字面量会被合并缓存,这基本上意味着有一个缓存区,大多称为字符串池。因此,字符串字面量始终是强引用,使它们不适合用作弱结构中的键,例如WeakReferenceWeakHashMap

自动装箱的int也是一样:同样,Integer为范围在[-128, 127]内的int值保留了一个Integer对象缓存。因此,在弱结构中也不应使用int作为键。

然而,您可以通过在插入条目时创建新对象来解决这些问题,例如在以下示例中,“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());

由于Integer的缓存,57的条目将永远留在那里,但是垃圾收集器可以删除56的条目。

Boolean也有缓存,但当然只有2个值。当Integer具有256个潜在危险值时,String实际上具有无限数量的可能危险出现 - 您只需要使用文字(或使用String.intern())来创建它们。可能还存在其他危险类。


2
在WeakHashMap中,将字符串字面量和字符串对象设置为“null”会产生不同的影响。原因是什么?
首先,您不能使对象为“null”。您可以将变量引用设置为“null”或引用对象,但是将对象设置为“null”不是存在的概念。 WeakHashMap的javadoc说明:
当其键不再被普通使用时,WeakHashMap中的条目将自动被删除。更确切地说,给定键的映射的存在不会防止垃圾收集器丢弃该键,即使它们在WeakHashMap中被引用。
在运行时,JVM会为加载类时看到的每个String字面量创建一个String对象。这些对象无论是否在WeakHashMap中被引用,都无法被GC,直到加载它们的ClassLoader被GC。
这类似于执行以下操作:
String wkey =  new String("weak");
String other = wkey;

如果您在其他地方有一个可访问的对象引用,即使在使用弱集合时,它也不能被GC回收。

另外请注意,System.gc()不能保证会运行垃圾回收。在使用时要注意不要误解结果。


0

如果将String作为键使用,那么它不适合WeakHashMap。这是因为当创建一个String对象时,JVM也会在字符串池中创建该对象。即使您已将引用设置为null,它们可能仍然在字符串池中保持强引用。

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());

运行上述代码后生成的输出为:
弱哈希映射:{键2=值2,键1=值1}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接