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 тоже → тот же эффект. По-прежнему не знаю, почему это происходит. Это действительно для меня разбойник
Ответы
Ответ 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
.