我正在测试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"))
则它是。< / p>
我使用Eclipse Memory Analyzer查看堆内容,并且在两种情况下都没有其他参考链而不是Soft。
如果有人对这种奇怪的行为有解释,我感兴趣。
答案 0 :(得分:2)
这很简单。出现在源代码中的字符串是intern,即保存在特殊池中,并且没有机会收集它,因为它是由您的方法的代码引用的。 <{1}}再次被调用时需要它,所以显然没有垃圾。
setName
的情况非常不同,因为这会创建原始字符串的副本。实际上,从this change到new String("name")
,不需要使用此构造函数。
我猜Eclipse Memory Analyzer没有显示字节码中包含的引用(因为没有人真正需要它)。
答案 1 :(得分: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都是对同一个String文字的引用。当您调用graph.setName(“name”)时,它正在创建对字符串文字的引用。引用字符串文字的字符串对象通常不被视为垃圾收集。这可以防止String对象被垃圾收集。
当你调用graph.setName(new String(“name”))时,它正在为新的String对象创建一个SoftReference。由于引用是新创建的对象而不是字符串文字,因此可以对其进行垃圾回收。