【问题标题】:Algorithms that lead to java.lang.OutOfMemoryError: PermGen space error导致 java.lang.OutOfMemoryError: PermGen space 错误的算法
【发布时间】:2011-04-20 19:57:52
【问题描述】:

我在 Sun JVM (1.6.0_21-b06) 上遇到 PermGen 空间错误(好的,它是 Oracle :))。增加选项 -XX:MaxPermGen 值没有帮助。我知道 PermGen 是一个用于存储类元数据等永久对象的空间。项目中的类数不是那么大 ~ 10 000。在崩溃之前 jvisualvm 显示 57MB 作为 Used PermGen。

我猜有些算法会占用所有可访问的内存。有人知道导致 PermGen 溢出的算法示例吗?

UPD. 我问了这么抽象的问题,因为此刻我无法使用任何分析器 - 代码崩溃如此严重以至于 jvisualvm 和 eclipse 停止响应。我需要使用 kill -KILL {process_numer} 从终端杀死 Java 进程。我使用具有许多线程和 JMS 消息传递的组织不良(但商业化)的代码。调试是一团糟——我首先需要知道在哪里查看。

【问题讨论】:

  • 你的问题的抽象级别杀死了;)。使用 Java 分析器(例如 virtualvm)找出程序崩溃的原因。如果您发现问题,请重写您的问题。
  • 出于好奇,您能否显示您正在使用的确切命令行选项?
  • 通过了解导致 PermGen 溢出的代码示例,您将获得什么?你是想欣赏一个问题,然后从欣赏中制造问题,还是试图解决它?这种解决问题的方法我见过很多次了,最好找根因解决。像 Skarab 建议使用 Java 分析器。了解您是研究人员还是学生,但看起来不像。
  • @Nulldevice 我看到你注意到 jms 消息。我遇到了与 JMS 相关的类似问题,请检查您的 jms 连接是否已关闭。在下面查看我的答案,它有更多详细信息。
  • 要提供更具建设性的反馈 - 请尝试eclipse.org/proposals/memory-analyzer。它是一个java转储内存分析器。在发生意外错误后非常有用。

标签: java heap-memory


【解决方案1】:

与其说是算法,不如说是实现。这是一种非常愚蠢的方法来生成填充 PermGen 空间的随机字符串:

    Random rnd = new Random();
    List<String> interned = new ArrayList<String>();
    for (;;) {
        int length = rnd.nextInt(100);
        StringBuilder builder = new StringBuilder();
        String chars = "abcdefghijklmnopqrstuvwxyz";
        for ( int i = 0; i < length; i++ ) {
            builder.append(chars.charAt(rnd.nextInt(chars.length())));
        }
        interned.add(builder.toString().intern());
    }

简而言之:实习字符串是一件会消耗 PermGen 内存的事情。

【讨论】:

    【解决方案2】:

    您是否使用其他垃圾收集器?

    如果花费太多时间进行垃圾收集,吞吐量收集器将抛出内存不足异常。例如,如果 JVM 花费超过 98% 的总时间来进行垃圾收集并且正在恢复不到 2% 的堆,它将引发内存不足的预期。此功能的实现在 1.5 中已更改。政策是相同的,但由于新的实施,行为可能会略有不同。” “在 J2SE 平台 1.5 版中,吞吐量收集器将被选为服务器类机器上的垃圾收集器。” http://java.sun.com/docs/hotspot/gc5.0/gc_tuning_5.html

    查看this页面上的一些说明。

    【讨论】:

      【解决方案3】:

      如果您非常频繁地使用java.lang.reflect.Proxy,那也会占用您的 PermGen 空间。

      【讨论】:

        【解决方案4】:

        有人知道导致 PermGen 溢出的算法示例吗?

        是的,但这有什么意义呢?如果你想解决这个问题,请安装一个内存分析工具,如 jprobe 或 lambda probe 并检查内存泄漏发生在哪里,然后修复它。 现在举个例子:有成千上万种方法可以超过 perm gen 空间。当我们继承了他们使用 JMS 的应用程序时,我注意到了一个项目。 jms 连接保持打开状态,应用程序在收到大量请求后几分钟内崩溃,并出现类似的错误。需要注意的是:当我们从 jboss 迁移到 weblogic(迁移到 beajrockit)时,它惊人地自我修复或至少承受了技术债务的打击。我的建议是不管这个,应该首先修复内存泄漏的错误代码,然后修改应用服务器和堆空间分配参数。

        这是一个有用的链接,其中包含有关您获得的异常的一些信息。 http://www.jroller.com/agileanswers/entry/preventing_java_s_java_lang

        编辑

        此链接可能会有所帮助 http://www.precisejava.com/javaperf/j2ee/JMS.htm

        【讨论】:

        • 我认为就我而言,您对 JMS 的想法是最有前景的。有些消息是在崩溃前发送的。
        • JMS框架的一点是它是异步的,可以接收多个异步请求,当jms连接不关闭时会导致问题。祝你好运。
        【解决方案5】:

        查看内存分析器 - http://www.eclipse.org/mat/。它是一个java转储内存分析器。在发生意外错误后非常有用。

        【讨论】:

          【解决方案6】:

          有两件事可能会导致永久代空间问题:

          1. String.intern(String) 方法在 PermGen 堆中创建字符串。如果你做了很多实习并直接(或间接)保留对实习字符串的引用,你可以填充 PermGen。

          2. 类加载器在 PermGen 堆中创建 JVM 内部类描述符和代码段。如果您的应用程序执行了大量动态类加载,并且类对象没有被垃圾回收,您可以填充 PermGen。

          Java webapps 的热重新部署依赖于动态加载,是 PermGen 常见的源问题。根本原因通常是内存泄漏,涉及从某个对象到旧类加载器的隐藏引用。 (Tomcat 经常为此“坚持”,但真正的问题通常出在正在重新部署的 web 应用程序中。)

          AFAIK,@Michael Borgwardt 提到的代理案例也是代理实现生成类文件并动态加载它们的结果。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2010-09-10
            • 2012-11-25
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-04-04
            • 1970-01-01
            相关资源
            最近更新 更多