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

2022-09-04 21:45:44

当我注意到我的客户端应用程序(基于Swing)上疯狂的高RAM使用率时,我开始研究它,这似乎与Spring中基于Notestin的配置有关。正如您将在下面的编辑中看到的那样,我意识到这只发生在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);
    }
}

消耗了大约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);
    }
}

打开帧不仅需要更长的时间,而且内存消耗在启动时飙升至160MB内存,然后稳定在大约152MB,这对我来说似乎很高。请记住,这只是最基本的情况,我开发的客户端应用程序atm已经占用了超过400MB,这对于旧机器来说太多了。

有人对这种行为有解释吗?我不明白。。

(顺便说一句,在这里使用3.1.1.发布。

编辑*正如axtaftt所建议的那样,我还尝试直接使用Test-Class作为参数来构造NotementConfigApplicationContext,因此不需要classpath-scan。不幸的是,没有改变任何关于内存消耗的东西。

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

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

基于 xml 的配置:

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

注释低音配置:

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

因此,在32位JVM上,两个proramms都很接近,这几乎是我所期望的。然而,在64位上,这是不同的。即使是第一个程序在64位上使用两倍的内存,这似乎已经太多了。尽管如此,它仍然不反对第二个程序,该程序在64位上使用的内存增加了近10倍。

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


答案 1

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

heap dump

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

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

allocation sites for java.lang.reflect.Method objects

这些似乎是在Spring试图找到从和超类继承了许多方法的setter时创建的。我没有仔细阅读相关代码,但作为验证此假设的快速测试,我做了以下操作:AnnotationConfigTestFramejava.awtjavax.swing

@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);
    }
}

即,不是从 继承的。现在,用于查找豆子的内存使用量相当低!AnnotationConfigTestFramejavax.swing.JFrame

这可能会为您提供进一步调试此项的提示。


答案 2

构造(提供带注释的类的基本包)的方式需要类路径扫描,因此需要时间和内存也就不足为奇了。AnnotationConfigApplicationContext

如果要避免类路径扫描,可以尝试使用 相应的构造函数来提供带注释的类(s 和 s)的精确集合。@Component@ConfigurationAnnotationConfigApplicationContext


推荐