Java中的垃圾收集是否发生在Java堆的perm区域?

3
我正在阅读这篇文章,它说:
堆的永久代或Perm区有些特殊,用于存储JVM中与类和方法相关的元数据,它还托管了JVM提供的字符串池,如我在我的字符串教程中讨论的为什么Java中的字符串是不可变的。关于Java中的垃圾回收是否发生在Perm区域,有很多不同的意见,据我所知,这取决于JVM,至少在Sun的JVM实现中会发生。您也可以通过创建数百万个字符串并观察垃圾回收或OutOfMemoryError来尝试此操作。
所以我有一个问题:
垃圾回收是否发生在Perm区域?如果不是,那么静态变量或方法和字符串字面值池如何被垃圾回收?

堆的不同“区域”的含义并非铁板钉钉——这取决于您特定的JVM使用的GC算法。但是,由系统或默认类加载器加载的任何类(以及类的静态成员)都永远不会变得可回收,因此可以安全地存放在堆的“永久”部分中。由其他类加载器加载的类是可能可回收的。 - Hot Licks
根据你引用的内容,我怀疑那个作者并不知道他在说什么。 - Hot Licks
@HotLicks,你所提到的作者是网络上最好的Java作者之一。 - Fresher
1
很抱歉听到这个消息。 - Hot Licks
2个回答

1

垃圾回收也会在堆的permgen空间中发生。

当它们各自的类加载器从内存中卸载时,静态变量也会被垃圾回收。

字符串文字池可能永远不会被垃圾回收。

编辑 如果permgen已满,则会发生OutOfMemoryError:PermGen


首先,“字符串字面量池”可能永远不会被垃圾回收。那么,如果它变满了会发生什么呢?其次,您能否提供您答案的来源? - Fresher
@Fresher - “字符串字面量池”不是内存中的“区域”,而是一组数据的概念分类。 - Hot Licks
“池化”字符串的理论上是可回收的。但是,关于数据同步存在一些小的复杂性,并且在“正常”情况下,大多数池化字符串都与已加载的类相关联(这些类大多不可回收),因此JVM在实践中可能会或可能不会尝试回收池。 - Hot Licks
@新手 - 但是池并不是一个具体的区域。字符串像任何其他对象一样占用堆空间。 - Hot Licks
@Batty,有没有避免 OutOfMemoryError : PermGen 的解决方案? - Fresher
显示剩余3条评论

1

垃圾回收确实会发生在permgen(基于Jvm实现)。我回答了一个关于如何故意填充perm gen的SO问题。JVM在permgen区域加载类等元数据。如果由于某种原因JVM的permgen不足,它可以决定卸载任何地方都没有引用的类。但是,GC何时运行或是否运行可能因JVM实现而异。

卸载类以创建空间是jvm在抛出“Outof memory:permgen space”之前的最后一招。

请查看此问题SO Link,这可能有帮助基本上,这显示了如何通过防止permgen区域的GC来填满permgen。


那么你同意上面的作者吗? - Fresher
当涉及到字符串时,这可能因JVM而异。但是所有JVM都会在堆中分配一个逻辑区域,从加载在permgen中的类中提取并保留所有字符串字面量。这样做是为了只保留一个字符串字面量副本。还可以参考此其他SO问题以进一步理解。https://dev59.com/IG445IYBdhLWcg3wUoxe - vkg
@vkg - "Logical" 是关键词。你无法指向堆中的任何“块”并说“这是字符串池”。除了标志表明它被 interned 之外,interned 字符串在堆中与任何其他字符串都无法区分。 - Hot Licks
@HotLicks 我认为我同意你的观点。但现在无法编辑我的评论。我会说在我之前的评论中看到链接,那里的答案解释得非常好。 - vkg

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