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