2014-12-02 82 views
1

我正在切换应用程序以使用spring并在运行时动态加载某些类。当通过maven运行基于JUnit的测试套件时,这种变化导致了一致的'java.lang.OutOfMemory:PermGen Space'错误。我们有大约800测试和OOM被抛出约200测试的代码更改如下:在JUnit中加载弹簧bean时发生OutOfMemory错误

private Obj buildMyObj() { 
    //Obj obj = MyObj(1); //Old method to get obj 
    ObjInterface obj = (ObjInterface) MyAppContext.INSTANCE.getApplicationContenxt().getBean("Obj"); 
} 

而且在XML文件中,我已经添加了以下内容:

<bean id="Obj" class="com.project.obj.ObjImplOne"> 
    <constructor-arg name="arg0" val="1"/> 
</bean> 

的buildMyObj()方法每个单元测试运行约一次,尽管有些会调用它多次。前面的方法,直接声明对象(在我们转到接口方法之前)工作正常。但是,现在我们已经有了一个接口并且可以在运行时使用几个不同的实现,我们需要在运行时加载它,而JUnit不会一直玩。

我跟进了一些现有的stackoverflow线程,看来每当Spring动态加载一个类时,它会将它放入PermGen中,但不够智能以识别该类的后续加载为完全相同,并导致每次调用在PermGen中放置一个新类,从而导致错误。建议允许使用'-XX:+ CMSClassUnloadingEnabled'JVM选项(建议为'-XX:+ CMSClassUnloadingEnabled -XX:+ CMSPermGenSweepingEnabled')来卸载类,但JVM抱怨“请使用CMSClassUnloadingEnabled替换CMSPermGenSweepingEnabled未来”

但这并没有改变任何东西,仍然抛出的错误

编辑:看测试套件运行在一个单独的终端监控顶部之后,它不会出现在JVM做任何东西回收正在加载的类。我提出每个建议的评论permgen大小,和java只是继续声称更长的时间内存(超过2演出的价值)是否有类加载和getBean()的问题?

+0

PermGen的VM参数添加到您的测试 - > -XX:MaxPermSize参数=256米 – 2014-12-02 17:45:22

+0

这并没有解决它 - 虽然增加PermGen的大小导致更多的测试正在运行,它最终像以前一样停滞 – user2093082 2014-12-02 17:58:23

+0

你的'MyAppContext.INSTANCE.getApplicationContenxt()。getBean(“Obj”)'做了什么?另外请注意,您必须关闭上下文,否则它将继续进食记忆。通常使用'getBean'是代码异味/不好的做法,应该避免,应该使用依赖注入。 – 2014-12-02 18:35:24

回答

1

解决方案是在xml文件中声明它时正确地限定bean的范围:Spring默认为singleton,我猜测这是为什么每次调用buildMyObj()时都会创建一个新的。设置范围为原型完全固定我的记忆问题:

<bean id="Obj" class="com.project.obj.ObjImplOne" scope="prototype"> 
    <constructor-arg name="arg0" val="1"/> 
</bean> 
相关问题