什么,除了Class对象,存储在Perm Gen Space(sun 1.6 VM)中?

时间:2011-06-14 17:31:48

标签: java jvm out-of-memory permgen maven-surefire-plugin

我在运行~300 JUnit测试并使用Spring上下文时看到'java.lang.OutOfMemoryError:PermGen space'。从那时起就很难搞清楚PermGen吃了什么:

  • 在稳定状态下,应用程序消耗约90m的permgen空间
  • 我尝试了-XX:MaxPermSize = 256m进行单元测试 - 仍然用完
  • 启用-XX:+TraceClassLoading-XX:+TraceClassUnloading后,我在OutOfMemoryError之前执行最后20-30次测试时看不到其他“加载”事件。

后者似乎表明除了Class对象之外的东西正在填充PermGen,不是吗?如果是这样,它会是什么?例如,是否存在类实例存储在PermGen中的情况?

这是我的VM信息:

$ java -version
java version "1.6.0_25"
Java(TM) SE Runtime Environment (build 1.6.0_25-b06)
Java HotSpot(TM) 64-Bit Server VM (build 20.0-b11, mixed mode)

相关

FWIW,我发现这个帖子的问题的根本证明是有点微不足道的:我假设Maven Surefire插件在它分叉VM时从MAVEN_OPTS(或运行mvn的VM实例)继承VM设置 - 它确实不是(嘘)。必须在插件的配置中明确指定使用argLine的那些。 HTH。

3 个答案:

答案 0 :(得分:4)

有时滥用String.intern()会导致PermGen空间错误,因为Interned String实例存储在PermGen中。

这可能就是您所看到的 - 尝试删除不必要的String.intern()调用以查看是否可以解决问题。一般情况下,我不建议使用String.intern(),除非你确定以下两个都是真的:

  • 您确定只会添加有限数量的字符串
  • 您实际上需要这样的字符串来共享相同的对象标识(例如,如果许多相同字符串的实例会消耗不可接受的内存量,或者出于复杂的性能原因需要依赖==进行字符串比较)

答案 1 :(得分:2)

Interned Strings也存储在permgen中,虽然不太可能有数百兆字符串的字符串。请记住,您使用代理的每个Spring Bean都会在运行时动态生成新类,以实现您正在代理的接口。 (或者你的类,如果你正在使用CGLIB代理等等)所以如果你为每个JUnit创建一个'新的'Spring ApplicationContext,你实际上是在为所有代理等创建300个副本。

还要记住Class的实例对于每个类加载器是唯一的,而不是在整个permgen空间中,因此实际上可能存在重复项,具体取决于运行的设置方式(如果它涉及在容器或部件中进行部署,尽管看起来似乎也是如此)不太可能在JUnit :))。

答案 2 :(得分:1)

我注意到你正在运行64位JVM。众所周知,它们会占用机器上实际内存的两倍,因为每次分配需要两倍的内存空间。

如果你有JUnit测试实际上加载了一个spring上下文(毕竟不是那么Unit),这些测试将实例化appContext中的所有bean。这很可能需要超过128mb(64位盒子上256mb)的内存。

根据我的经验,在64位计算机上为一个大型测试套件分配半个或更多的内容并不荒谬。尝试将其提升至512mb甚至1gb。

这些是我运行我的大型项目测试套件的选项......

-Xms256m
-Xmx512m
-XX:MaxPermSize=512m