Permgen是堆的一部分吗?

9

我在官方的Oracle网站上找到了一张图片enter image description here

但是在一个流行的SO答案中,我发现永久代不是堆的一部分。

永久代(非堆):包含虚拟机本身的所有反射数据的池,例如类和方法对象。对于使用类数据共享的Java VM,此代被划分为只读区域和读写区域。

我被这些矛盾的数据搞糊涂了。我相信两个地方的数据都是有效的,但有保留意见。请为我澄清这个问题。

P.S.

让我们只谈论Sun/Oracle jvms。

P.S.2

我已经阅读了jvm gcs(串行,并行,cms和g1)的解释,并且我没有看到关于permgen的提及,这表明永久代不是堆的一部分。


1
为什么Java这么令人困惑?我一直在阅读答案并在笔记本上记录了以下内容:静态方法(实际上所有方法)以及静态变量存储在PermGen堆的部分中,因为它们是反射数据的一部分(与实例相关的类相关数据)。我遵循了这个链接https://dev59.com/52oy5IYBdhLWcg3wsP_Q 但现在有人说永久代不是堆的一部分。我不知道该写/记住什么。请指导。 - Däñish Shärmà
3个回答

12
我相信你所提到的图表是来自于Oracle官网上的这里,他们引用了"permanent generation"作为堆区,但我认为这只是为了解释JVM内存中的"generations"。据我所知(并且我觉得很多专家也会同意),"permanent generation"并不属于堆区,它是非堆区的一部分,用于JVM内部的目的,如JIT优化、方法区等

Oracle官方参考资料

以下是我引用的三个Oracle官方参考资料,以帮助你确信"permanent generation"不属于堆区。

  1. Oracle jConsole指南
  2. Oracle GC开发人员博客
  3. Oracle GC调优文章

在上面的第一个链接中,您可以清楚地看到Java管理两种类型的内存 -堆内存和非堆内存,然后列出了每种类型内存中的"generations"。您可以阅读链接"监视内存消耗"中的此部分内容,下面是一些摘录。

enter image description here enter image description here

然后在上面的第二个链接中,GC开发者非常清楚地解释了"永久代(permanent generation)"的目的和见解,通过这个可以清晰地理解"永久代"不是堆(heap)的一部分,如下图所示:

图片描述

接着在上面的第三个链接中,你可以参考第3.2节“测量”中进行的内存测量,这也清楚地表明"永久代"不是堆的一部分。

而且,你会知道,在"老年代(Tenured generation)"进行完全垃圾回收(full GC)后,最坏情况下JVM可能会抛出内存不足异常,但不会将对象提升到"永久代",因为它不是堆的一部分。

非Oracle参考

查看下面的图表,还有许多这样的图表可用,可以解释JVM的内存调整参数。如果您从内存调整JVM参数的角度来看,它也是不言自明的,即"永久代"不是堆的一部分。

图片描述

最后

现在,我认为你应该清楚图表(及其文章)只是用来从"代"的角度解释JVM内存概念,但在实现中,JVM并不认为"永久代"是堆内存的一部分,可以将长期存在的对象提升到其中。


@gstackoverflow,您对此有任何问题或需要澄清的地方吗? - hagrawal7777

4

Java 8没有PermGen,但是MetaSpace提供了相同的功能,并且工作方式类似但不完全相同。

Java <= 7有一个PermGen,虽然它是由Java管理的空间,但它不是对象分配的同一堆,它不计入最大堆大小,也不计入CompressOops可寻址的32 GB限制,例如。它作为垃圾回收的一部分进行清理。

将其放入同一图表中是有意义的,但这并不意味着PermGen / MetaSpace是同一堆的一部分。

还要注意,当堆空间耗尽时,您会得到

java.lang.OutOfMemoryError: Heap space space

然而,当你的PermGen用尽时,会出现不同的错误。

java.lang.OutOfMemoryError: PermGen space

https://plumbr.eu/outofmemoryerror/java-heap-space

https://plumbr.eu/outofmemoryerror/permgen-space

https://plumbr.eu/outofmemoryerror/metaspace


1
JVM使用多个堆吗? - gstackoverflow
1
@gstackoverflow 它有多个管理内存区域,但实际上人们认为堆是唯一的区域。 - Peter Lawrey
因此,所描述的混淆术语是混淆的。人们称堆为[young gen] + [old gen],但Oracle将堆称为[young gen] + [old gen] + [perm gen]? - gstackoverflow
@gstackoverflow 实际上,最小/最大堆不包括PermGen,所以Oracle将PermGen包括在内是不一致的。 - Peter Lawrey

1

Permgen是Java 7及之前版本中固定大小的内存区域。它已在Java 8中被移除(发布说明)。我知道以下是移除背后的原因:

  1. hotshot和jrockit的合并
  2. 出现“java.lang.OutOfMemoryError:PermGen space”错误的应用程序进行字节码生成

自Java 8以来,原本存放在permgen中的内存对象被放置到metaspace中。Metaspace是可调整大小的内存区域,位于堆中。


2
我认为在Java 8中,PermGen已被Metaspace所取代。 - gstackoverflow
实际上你是对的,正确答案是“没有permgen”。 - Sergey Fedorov

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