我在Sun JVM上遇到了PermGen空间错误(1.6.0_21-b06)(好吧,这是Oracle :))。增加选项-XX:MaxPermGen值没有帮助。我知道PermGen是一个用于类元数据等永久对象的空间。项目中的班级数量不是很大~10 000.在崩溃之前,jvisualvm显示57MB作为二手PermGen。
我猜有些算法会占用所有可访问的内存。有人知道导致PermGen溢出的算法示例吗?
UPD。我问这样一个抽象的问题,因为此刻我无法使用任何探查器 - 代码崩溃如此之难以至于jvisualvm和eclipse停止响应。我需要使用kill -KILL {process_numer}从终端杀死java进程。我使用具有许多线程和JMS消息传递的糟糕的有组织(但商业)代码。调试是一团糟 - 我首先需要一些想法。
答案 0 :(得分:4)
算法并不像实现那么多。这是一个非常愚蠢的方法来生成填充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内存。
答案 1 :(得分:3)
有两件事可能会导致PermGen空间问题:
String.intern(String)
方法在PermGen堆中创建字符串。如果你做了很多实习并且直接(或间接)保留对实习字符串的引用,你可以填写PermGen。
类加载器在PermGen堆中创建JVM内部类描述符和代码段。如果您的应用程序执行了大量动态类加载,并且类对象没有收集垃圾,则可以填写PermGen。
Java webapps的热重新部署依赖于动态加载,并且是PermGen常见问题的根源。根本原因通常是内存泄漏,涉及从某个对象到旧类加载器的隐藏引用。 (Tomcat经常为此“坚持”,但真正的问题通常在于正在重新部署的webapp。)
AFAIK,@ Michael Borgwardt提到的代理案例也是Proxy实现生成类文件并动态加载它们的结果。
答案 2 :(得分:1)
如果您非常密集地使用java.lang.reflect.Proxy,那么也会占用您的PermGen空间。
答案 3 :(得分:1)
有人知道导致PermGen溢出的算法示例吗?
是的,但这有什么意义呢?如果你想修复这个安装内存探查器工具,如jprobe或lambda探测器,并检查内存泄漏发生的位置,并修复它。 现在举例来说:有数千种方法可以超越perm gen space。当我们继承了他们使用JMS的应用程序时,我注意到了一个项目。 jms连接保持打开状态,应用程序在收到大量请求后几分钟内崩溃,并出现类似的错误。需要注意的是:当我们从jboss(移动到beajrockit)转移到weblogic时,它惊人地固定了自己或至少遭受了技术债务的打击。我的建议与此无关,应首先修复内存泄漏的错误代码,然后修改app服务器和堆空间分配参数。
这是一个有用的链接,其中包含您获得的异常的一些信息。 http://www.jroller.com/agileanswers/entry/preventing_java_s_java_lang
修改强>
答案 4 :(得分:1)
查看内存分析器 - http://www.eclipse.org/mat/。它是一个java转储内存分析器。在发生意外错误后它非常有用。
答案 5 :(得分:0)
您使用的是不同的垃圾收集器吗?
如果花费太多时间进行垃圾收集,吞吐量收集器将抛出内存不足的异常。例如,如果JVM花费超过总时间的98%进行垃圾收集并且正在恢复少于2%的堆,则会导致内存不足。 1.5中已更改此功能的实现。策略是相同的,但由于新的实现,行为可能会略有不同。“”在J2SE平台版本1.5中,吞吐量收集器将被选为服务器类机器上的垃圾收集器。“http://java.sun.com/docs/hotspot/gc5.0/gc_tuning_5.html
查看this页上的一些说明。