简体   繁体   中英

spring annotation-based configuration - memory consumption too high?

As I noticed crazy high RAM usage on my client application (Swing-based), I started looking into it and it seems like this is somehow related to Annotation-based configuration in Spring. As you will see in my edits below, i realized that this occurs only on 64-Bit JVM.

See the following testcode:

xml-based configuration

<beans ....>
     <bean id="xmlConfigTest" class="at.test.XmlConfigTest" />
</beans>

public class XmlConfigTest extends JFrame {
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("config/applicationContext.xml");
        XmlConfigTest frame = (XmlConfigTest) ctx.getBean("xmlConfigTest");
        frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
        frame.setVisible(true);
    }
}

Uses up about 32MB memory, which seems ok to me.

Now the same with annotation based configuration :

@Service
public class AnnotationConfigTestFrame extends JFrame {
    public static void main(String[] args) throws InterruptedException {
        ApplicationContext ctx = new AnnotationConfigApplicationContext("at.test");

        AnnotationConfigTestFrame frame = (AnnotationConfigTestFrame) ctx
            .getBean("annotationConfigTestFrame");
       frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
       frame.setVisible(true);
    }
}

Not only takes it noticeable longer to open the frame, but the memory consumption sky-rockets to 160MB memory on startup and then levels off at about 152MB, which seems really high to me. And remember, this is only the most basic case, the client application i develope atm eats up over 400MB already, which is just too much for older machines.

Does anyone have an explanation for this behaviour? I don't understand..

(Using 3.1.1.RELEASE here btw.)

edit* As suggested by axtavt, i also tried to construct the AnnotationConfigApplicationContext directly with the Test-Class as Argument, so that no classpath-scan is necessary. Didn't changed anything about the memory consumption unfortunately.

edit 2 removed, see edit 3

edit 3 I now tested on the same machine (Windows 7 64-Bit) with both 32-Bit and 64-Bit JVM and the test-programms from above. This are the results:

xml based configuration:

32-Bit JVM: 16MB
64-Bit JVM: 31MB

annotation bassed configuration:

32-Bit JVM: 17MB
64-Bit JVM: 160MB

So on 32-Bit JVM both proramms are close, which is pretty much what i would expect. On 64-Bit though, this is different. Even the first programm uses twice as much memory on 64-Bit, which already seems to be too much. Still it's nothing against the second program, which uses nearly 10 times more memory on 64-Bit.

edit 4 Now tested under ubuntu too -> same effect. Still no idea why this is happening though. This is really a dealbreaker for me

At startup a large number of java.lang.reflect.Method objects are created.

堆转储

These objects are eligible for garbage collection, but in the case of your application it probably causes too many eden collections which results in high startup times.

Most of these java.lang.reflect.Method objects are allocated at the following site:

java.lang.reflect.Method对象的分配站点

These seem to be created when Spring tries to find setters on AnnotationConfigTestFrame which inherits lots of methods from java.awt and javax.swing super classes. I did not read through the relevant code closely, but as a quick test to verify this hypothesis, I did the following:

@Service
public class AnnotationConfigTestFrame /* extends JFrame */
{
    public static void main(String[] args) throws InterruptedException
    {
        ApplicationContext ctx = new AnnotationConfigApplicationContext(AnnotationConfigTestFrame.class);

        AnnotationConfigTestFrame frame = (AnnotationConfigTestFrame) ctx
                .getBean("annotationConfigTestFrame");
//        frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
//        frame.setVisible(true);

        waitABit();
        printRuntimeStats();
        System.exit(0);
    }
}

ie made AnnotationConfigTestFrame not inherit from javax.swing.JFrame . Now the memory usage for looking up the bean is reasonably low!

This might give you hints for debugging this further.

The way you construct your AnnotationConfigApplicationContext (providing a base package of your annotated classes) requires classpath scanning, therefore there is no surprise that it takes time and memory.

If you want to avoid classpath scanning, you can try to provide exact set of annotated classes ( @Component s and @Configuration s) instead, using the corresponding constuctor of AnnotationConfigApplicationContext .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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