【问题标题】:Garbage collection of String literals字符串文字的垃圾收集
【发布时间】:2013-02-25 18:38:57
【问题描述】:

我正在阅读有关垃圾收集的信息,当我搜索字符串文字垃圾收集时,我的搜索结果令人困惑。

我需要澄清以下几点:

  1. 如果一个字符串在编译时被定义为文字[例如:String str = "java"],那么它会被垃圾回收吗?

  2. 如果使用实习生方法 [例如:String str = new String("java").intern()] 那么它会被垃圾回收吗?它也将与第 1 点中的字符串文字区别对待。

  3. 有些地方提到,只有当String 类被卸载时,文字才会被垃圾回收?这是否有意义,因为我认为 String 类永远不会被卸载。

【问题讨论】:

  • 1 - stackoverflow.com/questions/2202162/… ; 2 - stackoverflow.com/questions/6470651/… ; 3 - String a = new String("asd") -> "a" 引用将被垃圾回收,但只是对 "asd" 的引用,而 "asd" 将永远存在。
  • 如果你搜索更多,你会发现一些地方提到使用实习生创建的字符串文字可以被垃圾收集,因为它们使用弱引用,但我无法确认,这就是我发布的原因很多不同的反应。
  • “从 Java 7 开始,Java String Pool 存储在 Heap 空间中,由 JVM 进行垃圾回收。这种方法的优点是降低了 OutOfMemory 错误的风险,因为未引用的字符串将从池中删除,从而释放内存。” Guide to Java String Pool by baeldung
  • Ole V.V.有正确答案

标签: java string garbage-collection


【解决方案1】:

在正常情况下,字符串字面量和类都分配到 JVM 的永久代(“PermGen”)中,通常不会被收集。被实习的字符串(例如 mystring.intern())存储在 permgen 中的 String 类拥有的内存池中,曾经有过激进的实习可能导致空间泄漏的情况,因为字符串池本身持有对每个字符串,即使不存在其他引用。显然这不再是真的,至少从 JDK 1.6 开始(参见,例如,here)。

有关 permgen 的更多信息,this 是对该主题的一个不错的概述。 (注意:该链接指向与产品关联的博客。我与博客、公司或产品没有任何关联,但博客条目很有用,与产品没有太大关系。 )

【讨论】:

  • 这是不正确的。 PermGen 空间>>被
  • 你当然是对的。我的意图只是说分配给 permgen 的数据在正常情况下不会被 GC 处理,但我措辞错误。稍作改写。
  • 实际上,深入挖掘,我发现实习字符串不会被垃圾收集不再是真的。 (这不是因为 permgen 空间,而是因为 String#intern 的实施。)更改我的答案以反映这一点。
  • 从来没有真实的字符串不会被垃圾收集。
【解决方案2】:
  1. 只要程序在内存中,文字字符串就会保留在内存中。
  2. str 将被垃圾收集,但创建它的文字不会。
  3. 这很有意义,因为卸载程序时字符串类也被卸载了。

【讨论】:

  • 你能给我一个可以卸载String的例子吗?我相信字符串文字也必须在 java 类中使用,并且字符串文字是常量,据我所知,卸载可能需要卸载 CLassLoader。你同意吗?
  • 据我所知,字符串文字不能以编程方式卸载。当程序终止时,它们将被卸载或销毁。
  • @fredrik - 如果已动态加载的类被卸载,它们也可以被垃圾收集。这可能在 JVM 正常运行时发生。
  • @StephenC 好的。很高兴知道。
【解决方案3】:

intern() 方法检查字符串池中对象的可用性。如果对象/文字可用,则将返回它的引用。如果池中没有文字,则将对象加载到永久区域(字符串池)中,然后将返回对它的引用。我们必须明智地使用intern() 方法。

【讨论】:

【解决方案4】:

如果一个字符串在编译时被定义为文字 [例如:String str = "java";] 那么它会被垃圾回收吗?

可能不会。代码对象将包含一个或多个对代表文字的 String 对象的引用。所以只要代码对象是可达的,String 对象就会到。

代码对象可能无法访问,但前提是它们是动态加载的......并且它们的类加载器被销毁。

如果我使用实习生方法 [例如:String str = new String("java").intern()] 那么它会被垃圾回收吗?

intern 调用返回的对象将与表示"java" 字符串文字的对象相同。 ("java" 文字在类加载时被实习。当你在你的代码 sn-p 中实习新构造的 String 对象时,它将查找并返回先前实习的 "java" 字符串。)

但是,与字符串字面量不同的实习字符串可以在它们变得无法访问时被垃圾回收。 PermGen 空间 在所有最近的 HotSpot JVM 上被垃圾收集。 (在 Java 8 之前...完全放弃 PermGen。)

它的处理方式也会与第 1 点中的字符串文字不同。

不...因为它与字符串文字是同一个对象。

事实上,一旦你理解了发生了什么,很明显字符串文字也没有被特殊对待。它只是“可达性”规则的应用......

有些地方提到,只有当String 类被卸载时,文字才会被垃圾收集?这是否有意义,因为我认为 String 类永远不会被卸载。

你是对的。这没有意义。说那是不正确的消息来源。 (如果您发布一个 URL 会很有帮助,这样我们就可以阅读他们自己所说的内容......)

【讨论】:

  • 对于#1,当你说包含对字符串字面量的引用的代码对象时,你指的是什么?
  • 在代码对象(字节码或本机编译)中的某处将有指令需要获取对应于字面量的 String 对象的引用。引用要么嵌入在代码本身中,要么存储在与代码关联的私有框架中。无论哪种方式,只要代码可以被执行,引用就是“可达的”。
  • 谢谢。而且,字符串实习生池是 JVM 中方法区的一部分吗?
  • 没有。它是一个单独的数据结构。但如果你真的有兴趣,我建议你下载 OpenJDK 源代码并自己查看。
猜你喜欢
  • 1970-01-01
  • 2013-02-15
  • 1970-01-01
  • 1970-01-01
  • 2013-05-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-17
相关资源
最近更新 更多