Java:为什么MaxPermSize存在?

为什么MaxPermSize存在?

这是一篇关于垃圾收集器中常设生成的好文章:

在Jon Masamitsu的博客上展示永久一代

编辑:

我没有看到任何可以表明为什么他们做出设计决定对永久发电机尺寸有最大限制的东西。 但我想这是出于几个原因。

  1. 它使实现起来更加容易,GC显然是非常重要的,因此以任何方式简化您的实现可能是一个好主意。

  2. YAGNI(你不需要它)大多数应用程序加载固定数量的类,通常它不是特别大,所以它们可能已针对常见情况进行了优化,只选择了一个合理的默认值并使其可配置。

  3. 假设你的perm gen大小正在增长到不可预测的大,那么你可能在类加载器中有一个错误(或者需要重新考虑你的架构)。 即使在运行时生成类(或执行其他此类技巧)的应用程序中,生成的类的数量通常也是固定的,因此您应该能够调整maxperm以满足您的需求。

  4. 我不是Java类加载和垃圾收集的所有细节的专家,但它们都是JVM的复杂部分,所以我想他们会尽量保持这两个组件尽可能正交,并允许perm gen增长动态地可能会以复杂的方式将这两个组件耦合在一起(特别是因为两个组件都有严重的线程考虑)

  5. 限制最大perm生成可能有一些性能优势,允许它增长可能涉及额外的集合复制,或者它可能意味着你的perm生成不再存在于连续的地址空间中,这可能会影响其他算法的方式管理集合的工作。

显然这些都是猜测。 但即使所有这些都是错误的我绝对不认为太阳选择固定尺寸是“愚蠢的”,可能有更多的工程和实施考虑因素,甚至可能是我梦寐以求:)

为了呈现略微不同的视角,IBM JVM没有permgen,而是去操作系统并根据需要分配内存块。 (谣言是jrockit做同样的事情,但我无法确认。)

这是有利的,因为你不会达到(看似)任意限制,需要针对合法的增长情况进行调整。

另一方面,对于失控的应用程序(基本上是泄漏类)来说,这是一个问题 – JVM本质上会占用地址空间中的所有内存。 这可能会导致错误,本机代码会突然失败malloc()调用,或Java以奇怪的方式破坏 – 比如无法分配新线程(这会消耗堆栈的内存)。 另一个缺点是它没有提供关于JVM的内存部分将消耗多少“成本确定性”。

所以这是一个权衡 – 你想如何在“潜在的不良”情景中失败?

它曾经用于确定最大的永久性发电量。 在某些算法中,或者如果你使用很多很多很多不同的类,你可以使用它。 给这个读一读。

但大多数情况下它被用作考试中的一个问题……

它的存在是因为它有助于调整JVM中的垃圾收集子系统。 根据底层架构和内存管理,JVM实现可能具有次优的垃圾收集(例如,太过苛刻)……您可以手动指定MaxPermSize而不是计算它,以便应用程序行为顺利…

Java GC Page说更多……

永久生成用于保持VM本身的reflection,例如类对象和方法对象。 这些reflection物体直接分配到永久世代中,并且其尺寸独立于其他世代。 通常,可以忽略此代的大小,因为默认大小足够。 但是,加载许多类的程序可能需要更大的永久代。

PermSize是用户设置的-Xmx值的附加单独堆空间。 为永久生成保留的堆部分包含JVM的所有reflection数据。 如果应用程序动态加载和卸载大量类以优化性能,则应相应地resize。 基本上,他堆存储对象,而perm gen保存有关其内部对象的信息。 因此,堆越大,需要的perm gen越大。

默认情况下,对于-client,MaxPermSize为32mb,对于-server,为128mb。 但是,如果未同时设置PermSize和MaxPermSize,则除非需要,否则整个堆不会增加。 当你设置PermSize和MaxPermSize时,例如192mb,额外的堆空间将在它启动时分配并保持分配。

也许您希望为您的用户提供应用程序将占用多少内存的选项,是的,操作系统确实有限制并且无论如何都会停止它,但也许用户希望能够在应用程序设置中限制它以便它们可以在一天之后用这个内存做其他事情而不会崩溃你的应用程序,因为它已经占用了那个空间并且因为它正在使用它而无法释放它。 因此,在设置菜单中,您有一个“我们使用的最大内存量”滑块,他们可以调整它,相应地调整MaxPermSize

通过使用MaxPermSize设置,您的应用程序将在启动时抛出GC Out of Memory错误,这样您就不会认为您的应用程序已启动并且正在运行并让您的客户呼叫,因为系统无法正常运行或非常缓慢。

假设您的VM上有4GB,并且您知道您的应用需要2gb的非烫发空间才能达到合同约定的性能指标。 如果您的perm gen将占用超过2gb,启动应用程序是没有意义的,因为您将无法满足您的工作说明中列出的性能指标。

最好知道在启动时,获取更多内存,或者重新配置VM以获取更多物理服务器内存(无论情况如何),而不是启动应用程序,允许类,ehcache或其他否则加载,认为一切都很好,然后从您的客户发现系统正在花费10秒钟加载页面。