简体   繁体   English

在JUnit中加载Spring bean时出现OutOfMemory错误

[英]OutOfMemory Error when loading spring beans in JUnit

I am in the process of switching an application to use spring and dynamically load some classes at runtime. 我正在切换应用程序以使用spring并在运行时动态加载某些类。 This change is leading to consistent 'java.lang.OutOfMemory: PermGen Space' errors when running our JUnit-based test suite through maven. 通过maven运行基于JUnit的测试套件时,此更改导致一致的“ java.lang.OutOfMemory:PermGen Space”错误。 We have about 800 tests, and the OoM is thrown about 200 tests in. The code changes are as follows: 我们有大约800个测试,并且OoM被投入了大约200个测试。代码更改如下:

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

And in the xml file, I have added the following: 在xml文件中,我添加了以下内容:

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

The buildMyObj() method is being run approximately once per unit test, though some will call it many times. 每个单元测试大约要运行一次buildMyObj()方法,尽管有些方法会多次调用它。 The previous method, declaring the object directly (before we moved to the interface approach) worked fine. 直接声明对象(在我们转向接口方法之前)的前一种方法效果很好。 However, now that we've got an interface and may use several different implementations at runtime, we need to load it at runtime and JUnit isn't playing along. 但是,既然我们已经有了一个接口并且可以在运行时使用几种不同的实现,那么我们需要在运行时加载它,并且JUnit不能正常运行。

I've followed up on some of the existing stackoverflow threads, and it appears that whenever Spring loads a class dynamically, it puts it in the PermGen, but isn't smart enough to identify a subsequent load of the class as identical and leads to every call placing a new class in the PermGen, hence the error. 我跟进了一些现有的stackoverflow线程,并且看来,每当Spring动态加载一个类时,它都会将其放入PermGen中,但是不够聪明,无法识别该类的后续加载是否相同并导致每个调用都会在PermGen中放置一个新类,因此会出错。 It was suggested to allow Class Unloading with the '-XX:+CMSClassUnloadingEnabled' JVM option (the suggestion was '-XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled', but the JVM complained with "Please use CMSClassUnloadingEnabled in place of CMSPermGenSweepingEnabled in the future" 建议使用“ -XX:+ CMSClassUnloadingEnabled” JVM选项允许类卸载(建议是“ -XX:+ CMSClassUnloadingEnabled -XX:+ CMSPermGenSweepingEnabled”,但JVM抱怨“请使用CMSClassUnloadingEnabled代替CMSPermGenSweepingEnabled”)。未来”

But that hasn't changed anything, the error is still being thrown. 但这并没有改变任何东西,错误仍然被抛出。

EDIT: After watching the test suite run and monitoring top in a separate terminal, it doesn't appear the JVM is doing anything to reclaim the classes which are being loaded. 编辑:观看测试套件的运行并在一个单独的终端中监视顶部之后,JVM似乎没有做任何事情来回收正在加载的类。 I uppoed the permgen size per a suggested comment, and java simply continued claiming memory for a longer time (over 2 gigs worth). 我根据建议的注释支持permgen的大小,而Java只是继续要求更长的时间(超过2个演出)。 Is there an issue with Class Loading and getBean()? 类加载和getBean()是否存在问题?

The solution was to properly scope the bean when declaring it in the xml file: Spring defaults to singleton, which I'm guessing is why a new one was created with every call to buildMyObj(). 解决方案是在xml文件中声明该bean时适当地确定其范围:Spring默认为singleton,这是为什么每次调用buildMyObj()都会创建一个新的bean的原因。 Setting the scope to prototype fixed my memory issues completely: 将范围设置为原型可完全解决我的内存问题:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM