2

我正在测试缓存实现的 SoftReference,我发现了一个奇怪的行为:

我有一个setName(String name)通过 SoftReference 设置 Graph 对象名称的方法:

public void setName(String newName) {
    getData().name = new SoftReference<String>(newName,garbagedData);
}

(garbagedData 是一个 ReferenceQueue,在这个特定问题中似乎并不重要)。

当我graph.setName("name");从主线程调用时,并且当 à 强制OutOfMemory出错时,引用指向的值不会被垃圾,但如果我调用graph.setName(new String("name")),那么它就是。

我用 Eclipse 内存分析器查看堆内容,在这两种情况下,除了 Soft 之外,没有其他引用链。

如果有人对这种奇怪的行为有解释,我很感兴趣。

4

2 回答 2

2

这很简单。出现在源代码中的字符串是intern ed,即保存在一个特殊的池中,并且没有机会收集它,因为它被您的方法的代码引用。再次调用时需要它setName,所以它显然不是垃圾。

情况new String("name")非常不同,因为这会创建原始字符串的副本。实际上,没有必要使用这个构造函数,因为这个更改String.substring.

我猜 Eclipse 内存分析器没有显示字节码中包含的引用(因为没有人真正需要它)。

于 2014-02-06T23:43:16.527 回答
0

您持有对 String 对象的 SoftReference。对于 String 对象,JVM 管理 String 文字的方式与 String 对象不同。

String a = new String("test");
String b = new String("test");

在此示例中,实例 a 和 b 是对不同对象的引用。

String a = "test";
String b = "test";

这里 a 和 b 都是对相同字符串文字的引用。当您调用 graph.setName("name") 时,它正在创建对字符串文字的引用。引用字符串文字的字符串对象通常不考虑进行垃圾回收。这可以防止 String 对象被垃圾收集。

当您调用 graph.setName(new String("name")) 时,它正在为新的 String 对象创建一个 SoftReference。由于引用是对新创建的对象而不是字符串文字,因此它可以被垃圾收集。

于 2014-02-06T23:47:49.063 回答