基于spring注释的配置 - 内存消耗过高?

Mar*_*o B 13 java spring jvm spring-annotations

当我注意到我的客户端应用程序(基于Swing)上使用疯狂的高RAM时,我开始研究它,看起来这与Spring中基于Annotation的配置有某种关系.正如您将在下面的编辑中看到的那样,我意识到这只发生在64位JVM上.

请参阅以下测试代码:

基于xml的配置

<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);
    }
}
Run Code Online (Sandbox Code Playgroud)

使用大约32MB内存,这对我来说似乎没问题.

现在与基于注释的配置相同:

@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);
    }
}
Run Code Online (Sandbox Code Playgroud)

打开相框不仅要花费更长的时间,而且在启动时内存消耗量会升至160MB内存,然后在大约152MB处达到平衡,这对我来说似乎非常高.请记住,这只是最基本的情况,我开发的客户端应用程序已经超过400MB,这对于旧机器来说太多了.

有没有人对这种行为有解释?我不明白..

(在这里使用3.1.1.RELEASE顺便说一下.)

编辑* 正如axtavt所建议的,我还尝试直接用Test-Class作为Argument构造AnnotationConfigApplicationContext,这样就不需要类路径扫描.遗憾的是,没有改变内存消耗.

编辑2已删除,请参阅编辑3

编辑3 我现在使用32位和64位JVM以及上面的测试程序在同一台机器(Windows 7 64位)上进行了测试.这是结果:

基于xml的配置:

32-Bit JVM: 16MB
64-Bit JVM: 31MB
Run Code Online (Sandbox Code Playgroud)

注释基础配置:

32-Bit JVM: 17MB
64-Bit JVM: 160MB
Run Code Online (Sandbox Code Playgroud)

所以在32位JVM上,两个项目都很接近,这正是我所期望的.但在64位上,这是不同的.即便是第一个程序在64位上使用两倍的内存,这似乎已经太多了.对于第二个程序来说,它仍然没什么,它在64位上使用了近10倍的内存.

编辑4 现在在ubuntu下测试 - >效果相同.仍然不知道为什么会发生这种情况.这对我来说真的是一个破坏者

Bin*_*mas 7

启动时java.lang.reflect.Method会创建大量对象.

堆转储

这些对象符合垃圾回收的条件,但对于您的应用程序,它可能会导致过多的eden集合,从而导致启动时间过长.

大多数这些java.lang.reflect.Method对象都在以下站点分配:

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

这些似乎是在Spring试图找到AnnotationConfigTestFrame继承了大量方法java.awtjavax.swing超类的setter时创建的.我没有仔细阅读相关代码,但作为验证这一假设的快速测试,我做了以下工作:

@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);
    }
}
Run Code Online (Sandbox Code Playgroud)

AnnotationConfigTestFrame不是继承自javax.swing.JFrame.现在查找bean的内存使用率相当低!

这可能会为您提供进一步调试的提示.


axt*_*avt 5

您构建自己的方式AnnotationConfigApplicationContext(提供带注释类的基础包)需要进行类路径扫描,因此毫不奇怪它需要时间和内存.

如果要避免类路径扫描,可以尝试使用相应的构造函数来提供精确的带注释类(@Components和@Configurations)AnnotationConfigApplicationContext.