Подтвердить что ты не робот

Spring конфигурация на основе аннотации - слишком большое потребление памяти?

Как я заметил безумное использование ОЗУ в моем клиентском приложении (Swing-based), я начал изучать его, и похоже, что это как-то связано с конфигурацией на основе аннотаций в Spring. Как вы увидите в моих праведниках ниже, я понял, что это происходит только на 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);
    }
}

Использует память около 32 МБ, что мне кажется хорошо.

Теперь то же самое с конфигурацией на основе аннотаций:

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

Не только становится заметным дольше, чтобы открыть фрейм, но потребление памяти ракеты до 160 МБ памяти при запуске, а затем выравнивается примерно на 152 МБ, что кажется мне действительно высоким. И помните, что это только самый простой случай, клиентское приложение, которое я разрабатываю, уже более 400 МБ, что слишком много для старых машин.

Есть ли у кого-нибудь объяснения этого поведения? Я не понимаю..

(Используя 3.1.1.RELEASE here btw.)

изменить * Как было предложено axtavt, я также попытался построить AnnotationConfigApplicationContext непосредственно с Test-Class в качестве аргумента, чтобы не требовалось сканирование путей. К сожалению, ничего не изменило о потреблении памяти.

отредактировать 2 удален, см. edit 3

изменить 3 Теперь я тестировал на одном компьютере (64-разрядный Windows 7) с 32-разрядной и 64-разрядной JVM и тестовыми программами сверху. Вот результаты:

xml:

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

аннотация: басовая конфигурация:

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

Итак, на 32-битной JVM обе прораммы близки, и это в значительной степени то, чего я ожидал бы. Однако в 64-битном режиме это отличается. Даже первая программа использует в два раза больше памяти на 64-битных, что уже кажется слишком большим. Тем не менее это ничего не касается второй программы, которая использует в 64-битной памяти почти в 10 раз больше.

изменить 4 Теперь тестируется под ubuntu тоже → тот же эффект. По-прежнему не знаю, почему это происходит. Это действительно для меня разбойник

4b9b3361

Ответ 1

При запуске создается большое количество объектов java.lang.reflect.Method.

heap dump

Эти объекты имеют право на сбор мусора, но в случае вашего приложения это, вероятно, вызывает слишком много коллекций eden, что приводит к большим временам запуска.

Большинство из этих объектов java.lang.reflect.Method выделяются на следующем сайте:

allocation sites for java.lang.reflect.Method objects

Кажется, что они созданы, когда Spring пытается найти сеттеры на AnnotationConfigTestFrame, который наследует множество методов из java.awt и javax.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);
    }
}

то есть. сделанный AnnotationConfigTestFrame не наследуется от javax.swing.JFrame. Теперь использование памяти для поиска bean достаточно низкое!

Это может дать вам подсказки для дальнейшей отладки.

Ответ 2

Как вы создаете свой AnnotationConfigApplicationContext (предоставляя базовый пакет ваших аннотированных классов), требуется сканирование классов, поэтому нет ничего удивительного в том, что для этого требуется время и память.

Если вы хотите избежать сканирования пути к классам, вы можете попытаться предоставить точный набор аннотированных классов (@Component и @Configuration s) вместо этого, используя соответствующий constuctor AnnotationConfigApplicationContext.