java - una - configuración basada en la anotación de primavera: ¿el consumo de memoria es demasiado alto?
las notas de credito se declaran (2)
La forma en que construyes tu AnnotationConfigApplicationContext
(que proporciona un paquete base de tus clases anotadas) requiere un escaneo classpath, por lo tanto, no es de extrañar que lleve tiempo y memoria.
Si desea evitar el análisis de classpath, puede intentar proporcionar el conjunto exacto de clases anotadas ( @Component
s y @Configuration
s) en su lugar, utilizando el constuctor correspondiente de AnnotationConfigApplicationContext
.
Cuando noté un gran uso de RAM en mi aplicación cliente (basada en Swing), comencé a investigar y parece que de alguna manera está relacionado con la configuración basada en Annotation en Spring. Como verá en mis ediciones a continuación, me di cuenta de que esto ocurre solo en JVM de 64 bits.
Vea el siguiente código de prueba:
configuración basada en 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);
}
}
Utiliza hasta 32 MB de memoria, lo que me parece bien.
Ahora lo mismo con la configuración basada en anotaciones :
@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);
}
}
No solo se nota más tiempo para abrir el marco, sino que el consumo de memoria se dispara a 160MB de memoria al arrancar y luego se nivela a unos 152MB, lo cual me parece muy importante. Y recuerde, este es solo el caso más básico, la aplicación cliente i develope atm consume más de 400 MB, lo que es demasiado para máquinas antiguas.
¿Alguien tiene una explicación para este comportamiento? No entiendo..
(Usando 3.1.1.RELEASE aquí por cierto)
editar * Como sugiere axtavt, también intenté construir el AnnotationConfigApplicationContext directamente con Test-Class como argumento, por lo que no es necesario ningún classpath-scan. No cambió nada sobre el consumo de memoria, lamentablemente.
editar 2 eliminado, ver edición 3
edit 3 Ahora probé en la misma máquina (Windows 7 de 64 bits) con JVM de 32 y 64 bits y los programas de prueba desde arriba. Estos son los resultados:
configuración basada en xml:
32-Bit JVM: 16MB
64-Bit JVM: 31MB
configuración basada en la anotación:
32-Bit JVM: 17MB
64-Bit JVM: 160MB
Entonces, en JVM de 32 bits ambos programas están cerca, que es más o menos lo que esperaría. Sin embargo, en 64 bits, esto es diferente. Incluso el primer programa utiliza el doble de memoria en 64 bits, que ya parece ser demasiado. Todavía no es nada en contra del segundo programa, que usa casi 10 veces más memoria en 64 bits.
editar 4 Ahora probado bajo ubuntu también -> mismo efecto. Todavía no tengo idea de por qué está pasando esto. Esto es realmente un obstáculo para mí
Al inicio, se crean una gran cantidad de objetos java.lang.reflect.Method
.
Estos objetos son elegibles para la recolección de basura, pero en el caso de su aplicación probablemente cause demasiadas colecciones de eden, lo que resulta en tiempos de inicio altos.
La mayoría de estos objetos java.lang.reflect.Method
se asignan en el siguiente sitio:
Parece que se crean cuando Spring intenta encontrar setters en AnnotationConfigTestFrame
que hereda muchos métodos de las super clases de java.awt
y javax.swing
. No leí atentamente el código relevante, pero como una prueba rápida para verificar esta hipótesis, hice lo siguiente:
@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);
}
}
es decir, que AnnotationConfigTestFrame
no hereda de javax.swing.JFrame
. ¡Ahora el uso de la memoria para buscar el frijol es razonablemente bajo!
Esto podría darte pistas para depurar esto más.