【问题标题】:SoftReference<String> not garbage collected when out of memorySoftReference<String> 内存不足时不会被垃圾收集
【发布时间】:2014-03-04 03:42:50
【问题描述】:

我正在测试缓存实现的 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 内存分析器查看堆内容,在这两种情况下,除了软引用链之外,没有其他引用链。

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

【问题讨论】:

  • 内存有限的缓存是一个非常糟糕的主意:旧项目将被保存很长时间。
  • @kdgregory:我同意这是一个坏主意,但大多数情况下你根本无法控制。但是您通常无法判断“使用寿命”是多少,并且无法平衡不同的缓存(例如:您必须决定诸如“缓存 1 的限制是否应为 1000 个条目?”而不是“让缓存 1和 cache-2 一起使用不超过 100 MB")。
  • 就我而言,“使用寿命”是最长的。但是如果我使用强引用,可能会出现内存不足。 @kdgregory:如果 gc 可以在需要时删除它们,那么将对象保存在内存中是一件坏事吗? @maaartinus:我总是可以手动将引用设置为 null 并限制缓存大小,我错了吗?

标签: java garbage-collection soft-references


【解决方案1】:

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

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

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

【讨论】:

  • 谢谢,我不知道实习生字符串和这个特殊的池。我怀疑这样的优化。关于String.substring 的更改,这意味着我只需要调用substring(0) 而不是构造函数?这对我来说似乎不是很明确。
  • @zelus:不。在此更改之前,每个字符串都有一个指向可能共享的char[] 和一个offsetlength 的指针。所以String s = aVeryLongString.substring(0, 1) 是一个非常快的操作,但是你得到了一个指向巨大的char[] 的对象。为了解决这个问题,您可以使用new String(s),它复制了数组的所需部分。更改后,substring 执行复制,因此不再使用构造函数。您也不应该用substring(0) 或其他任何东西替换它。完全不需要。
【解决方案2】:

您持有对 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。由于引用是对新创建的对象而不是字符串字面量,因此它可以被垃圾回收。

【讨论】:

    猜你喜欢
    • 2011-08-11
    • 2012-06-12
    • 1970-01-01
    • 1970-01-01
    • 2021-11-22
    • 2019-05-15
    • 1970-01-01
    • 1970-01-01
    • 2012-06-28
    相关资源
    最近更新 更多