【问题标题】:Java: Why does MaxPermSize exist?Java:为什么存在 MaxPermSize?
【发布时间】:2011-03-22 07:47:13
【问题描述】:

为什么存在 MaxPermSize?

【问题讨论】:

    标签: java jvm


    【解决方案1】:

    它用于确定最大永久代的大小。在某些算法中,或者如果您使用很多很多不同的类,您可以使用它。阅读this one

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

    【讨论】:

    • 这只是说明它是什么,并没有解释它为什么存在。
    【解决方案2】:

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

    Java GC Page says more...

    【讨论】:

    • 但是为什么首先要有最大尺寸呢?为什么不让它增长,直到达到操作系统对进程内存大小的限制?
    • @JonathanAllen 我以前在基于容器的虚拟化解决方案 (OpenVZ) 中看到过问题,其中 Java 或其他一些进程看到了物理主机的可用内存,并且 /assumed/ 它有足够的可用内存。最终,容器控制器因超出内存限制而终止了进程。 MaxPermSize 可以在这种情况下提供帮助,让我告诉虚拟机实际上有多少内存可用。
    【解决方案3】:

    这里有一篇关于垃圾收集器中永久代的好文章:

    Presenting the Permanent GenerationJon Masamitsu's Weblog

    编辑:

    我没有看到任何可以说明他们为什么做出设计决定来对永久代大小设置最大限制。但我想这样做有几个原因。

    1. 它使实现变得更加容易,GC 绝对不是微不足道的,因此以任何方式简化您的实现可能是一个好主意。

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

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

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

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

    显然这些都是猜测。但即使所有这些都是错误的,我绝对不认为 sun 选择固定尺寸是“愚蠢的”,可能有比我想象的更多的工程和实施考虑:)

    【讨论】:

    • 这并没有说明为什么他们决定给它一个任意的最大尺寸。如果它像任何其他应用程序一样,您只需一次为一个页面分配更多空间,直到达到操作系统限制。
    • 除非他们需要将整个堆预先分配为连续块,我不相信,否则您实际上会通过引入最大大小来增加复杂性。而且与线程的堆栈不同,我想不出你需要一个连续块的任何理由。
    • perm gen 大小的管理方式与“常规”堆不同(链接文章提到了这一点),实际上它是预先分配的。
    • 答案中的链接已损坏(来自 Sun 的重定向错误),但此链接现在有效:blogs.oracle.com/jonthecollector/entry/…
    【解决方案4】:

    从稍微不同的角度来看,IBM JVM 没有 permgen,而是向操作系统发送并根据需要分配内存块。 (有传言说 jrockit 也是这样,但我无法确定。)

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

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

    所以这是一个权衡 - 你想如何在“潜在的坏事”场景中失败?

    【讨论】:

      【解决方案5】:

      永久代用于保存 VM 本身的反射,例如类对象和方法对象。这些反射对象被直接分配到永久代,并且它的大小独立于其他代。通常,可以忽略这一代的大小,因为默认大小已经足够了。但是,加载许多类的程序可能需要更大的永久代。

      PermSize 是用户设置的 -Xmx 值的额外独立堆空间。为永久代保留的堆部分包含 JVM 的所有反射数据。如果您的应用程序动态加载和卸载大量类以优化性能,您应该相应地调整大小。基本上,他堆存储对象,而 perm gen 在其中保存有关对象的信息。因此,堆越大,perm gen 就需要越大。

      默认情况下,-client 的 MaxPermSize 为 32mb,-server 的 MaxPermSize 为 64mb。但是,如果您没有同时设置 PermSize 和 MaxPermSize,除非需要,否则总体堆不会增加。当您同时设置 PermSize 和 MaxPermSize 时,例如 192mb,额外的堆空间将在启动时分配并保持分配状态。

      【讨论】:

        【解决方案6】:

        也许您想让您的用户选择您的应用程序将占用多少内存,是的,操作系统确实有限制并且无论如何都会停止它,但也许用户希望能够在应用程序设置中限制它这样他们就可以在当天晚些时候用该内存做其他事情而不会导致您的应用崩溃,因为它已经占用了该空间并且无法释放它,因为它正在使用它。因此,在设置菜单中,您有一个“我们使用的最大内存量”滑块,他们可以对其进行调整,从而相应地调整 MaxPermSize

        【讨论】:

          【解决方案7】:

          通过设置 MaxPermSize,您的应用将在启动时抛出 GC Out of Memory 错误,这样您就不会认为您的应用已启动并正在运行,并且您的客户不会因为系统不工作或非常缓慢而打电话.

          假设您的虚拟机上有 4gb 的空间,并且您知道您的应用需要 2gb 的 non-perm 空间才能达到合同约定的性能指标。如果您的 perm gen 将占用超过 2gb,则启动该应用程序没有意义,因为您将无法达到工作说明中列出的性能指标。

          最好知道在启动时,将更多内存放入盒子,或重新配置您的 VM 以占用更多物理服务器内存(无论情况如何),而不是启动应用程序,允许类,ehcache ,或其他要加载的内容,认为一切正常,然后从您的客户那里得知系统加载页面需要 10 秒。

          【讨论】:

          • 不,MaxPermSize 确实保证如果你的应用加载太多类,它会在启动时失败。 Java 可以(并且将)根据需要在运行时加载类,因此只有在例如某个方法第一次运行,并加载所需的类。
          猜你喜欢
          • 2012-03-27
          • 2016-07-18
          • 2019-02-21
          • 2015-07-04
          • 2011-05-04
          • 1970-01-01
          • 1970-01-01
          • 2016-02-28
          • 1970-01-01
          相关资源
          最近更新 更多