¿Cómo reducir el uso de memoria de arranque de primavera?

6 minutos de lectura

Avatar de usuario de Hailong Li
hailong li

Estoy usando Spring Boot para desarrollar una aplicación cliente. y cuando se ejecuta la aplicación Spring Boot (usando un jar completamente ejecutable), el uso de la memoria es de aproximadamente 190M en el servidor x64 y 110M en el servidor x86.

Mis opciones de JVM son (-Xmx64M -Xms64M -XX:MaxPermSize=64M -server), ¿por qué en el servidor x64, el uso de memoria es tan grande? ¿Cómo reducir el uso de memoria por debajo de 150M?

gracias.

  • Los punteros x64 (64 bits) son dos veces más grandes que los punteros x86 (32 bits), por lo que el uso de la memoria en el modo de 64 bits será necesariamente mayor.

    – Andreas

    12 de junio de 2017 a las 4:27

  • sí, pero no sé qué memoria se usa excepto heap + Perm. Configuré el tamaño máximo de almacenamiento dinámico en 64M, el tamaño máximo de permiso en 64M, pero ¿por qué se usan alrededor de 60M (190M – 64Mx2) y no puedo reducirlo?

    -Hailong Li

    12 de junio de 2017 a las 5:26


  • @HailongLi mencionó lo que está causando el aumento de la memoria. Pero, ¿cómo reducirlo?

    – Krish

    12 de mayo de 2018 a las 9:33

  • Un poco más tarde, pero esta publicación puede ayudar dzone.com/articulos/…

    – Sigrist

    21/09/2018 a las 14:35

Avatar de usuario de CCob
CCob

Un poco tarde para el juego aquí, pero sufrí el mismo problema con una aplicación Spring Boot en contenedor en Docker. Lo mínimo con lo que se saldrá con la suya es alrededor de 72 millones de memoria total en las aplicaciones Spring Boot más simples con un solo controlador y Tomcat integrado. Agregue Spring Data REST, Spring Security y algunas entidades JPA y verá un mínimo de 200M-300M. Puede obtener una aplicación Spring Boot simple hasta alrededor de 72 millones en total utilizando las siguientes opciones de JVM.

Con -XX:+UseSerialGC Esto realizará la recolección de elementos no utilizados en línea con el subproceso que asigna la memoria del montón en lugar de uno o varios subprocesos de GC dedicados.

Con -Xss512k Esto limitará la memoria de pila de cada subproceso a 512 KB en lugar del valor predeterminado de 1 MB.

Con -XX:MaxRAM=72m Esto restringirá los cálculos de la JVM para la memoria administrada en montón y no en montón para estar dentro de los límites de este valor.

Además de las opciones de JVM anteriores, también puede usar la siguiente propiedad dentro de su application.properties archivo:

server.tomcat.max-threads = 1 Esto limitará la cantidad de subprocesos del controlador de solicitudes HTTP a 1 (el valor predeterminado es 200)


Aquí hay un ejemplo de docker stats corriendo un muy simple aplicación Spring Boot con los límites anteriores y con la ventana acoplable -m 72m argumento. Si disminuyo los valores por debajo de esto, no puedo hacer que la aplicación se inicie.

83ccc9b2156d: Mem Usage: 70.36MiB / 72MiB | Mem Percentage: 97.72%

Y aquí puede ver un desglose de toda la memoria de montón nativa y de Java al salir.

Native Memory Tracking:

Total: reserved=1398681KB, committed=112996KB
-                 Java Heap (reserved=36864KB, committed=36260KB)
                            (mmap: reserved=36864KB, committed=36260KB) 

-                     Class (reserved=1086709KB, committed=43381KB)
                            (classes #7548)
                            (  instance classes #7049, array classes #499)
                            (malloc=1269KB #19354) 
                            (mmap: reserved=1085440KB, committed=42112KB) 
                            (  Metadata:   )
                            (    reserved=36864KB, committed=36864KB)
                            (    used=36161KB)
                            (    free=703KB)
                            (    waste=0KB =0.00%)
                            (  Class space:)
                            (    reserved=1048576KB, committed=5248KB)
                            (    used=4801KB)
                            (    free=447KB)
                            (    waste=0KB =0.00%)

-                    Thread (reserved=9319KB, committed=938KB)
                            (thread #14)
                            (stack: reserved=9253KB, committed=872KB)
                            (malloc=50KB #74) 
                            (arena=16KB #26)

-                      Code (reserved=248678KB, committed=15310KB)
                            (malloc=990KB #4592) 
                            (mmap: reserved=247688KB, committed=14320KB) 

-                        GC (reserved=400KB, committed=396KB)
                            (malloc=272KB #874) 
                            (mmap: reserved=128KB, committed=124KB) 

-                  Compiler (reserved=276KB, committed=276KB)
                            (malloc=17KB #409) 
                            (arena=260KB #6)

-                  Internal (reserved=660KB, committed=660KB)
                            (malloc=620KB #1880) 
                            (mmap: reserved=40KB, committed=40KB) 

-                    Symbol (reserved=11174KB, committed=11174KB)
                            (malloc=8417KB #88784) 
                            (arena=2757KB #1)

-    Native Memory Tracking (reserved=1858KB, committed=1858KB)
                            (malloc=6KB #80) 
                            (tracking overhead=1852KB)

-               Arena Chunk (reserved=2583KB, committed=2583KB)
                            (malloc=2583KB) 

-                   Logging (reserved=4KB, committed=4KB)
                            (malloc=4KB #179) 

-                 Arguments (reserved=17KB, committed=17KB)
                            (malloc=17KB #470) 

-                    Module (reserved=137KB, committed=137KB)
                            (malloc=137KB #1616)

Tampoco espere obtener un rendimiento decente de esto, ya que me imagino que el GC se ejecutaría con frecuencia con esta configuración, ya que no tiene mucha memoria libre para jugar.

  • Salvavidas en 2020 con el -XX:MaxRAM configuración para mi heroku dyno arrojando constantemente fallas R14

    – kmek

    17 de abril de 2020 a las 6:23

  • 72MB?! ¡¡Ja!! Sí claro, mi aplicación empieza en 950 MB. Spring boot 2.3.0, nada más que unos pocos controladores REST. Tarda menos de 10 segundos en iniciarse, pero incluso sin recibir ninguna solicitud, sin ponerle ninguna carga, se dispara hasta 1 GB y se queda allí.

    – GeneralJames

    14 de diciembre de 2020 a las 9:34

  • @JeneralJames Esto me está pasando exactamente en producción. Y cada vez más siento que esta no es la tecnología para el mundo en contenedores. Esto está realmente hecho para un servidor de aplicaciones monolítico y cientos de puntos finales (controladores). Es por eso que la tecnología más nueva en el espacio de Java, como Quarkus, está surgiendo para abordar exactamente este problema. Plataformas aún mejores como Node/Go/.net core, que se basan en arcos nativos de nube/contenedor.

    -shakeel osmani

    28 de febrero de 2021 a las 20:22

Avatar de usuario de Hailong Li
hailong li

Después de la búsqueda, descubrí que ya tiene una respuesta en stackoveflow. El consumo de memoria Spring Boot aumenta más allá de la opción -Xmx

1. Number of http threads (Undertow starts around 50 threads per default, but you can increase / decrease via property the amount of threads needed)
2. Access to native routines (.dll, .so) via JNI
3. Static variables
4. Use of cache (memcache, ehcache, etc)
If a VM is 32 bit or 64 bit, 64 bit uses more memory to run the same application, so if you don't need a heap bigger than 1.5GB, so keep your application runnnig over 32 bit to save memory.

porque Spring Boot comienza alrededor de 50 subprocesos por defecto para el servicio http (Tomcat o Undertow, Jetty), y su uso es de 1 MB por subproceso (configuración predeterminada de jvm de 64 bits).

Entonces, en jvm de 64 bits, el uso de memoria es heap (64M) + Permgen (max 64M) + pilas de subprocesos (1M x 50+) + identificadores nativos.

referencias:

  • ¿Cómo reducir este tamaño de memoria? ¿Es debido al servidor tomcat incrustado en el archivo jar? si lo ejecutamos como memoria de archivo de guerra se reducirá?

    – Krish

    11 mayo 2018 a las 18:31

  • Esta respuesta aceptada no responde a la pregunta. La pregunta era cómo reducir el consumo de memoria, no explicar por qué estaba usando mucha memoria.

    – Miguel

    24/07/2018 a las 18:30

  • ¿Por qué esto tiene 5 votos a favor? simplemente responde la pregunta en parte

    – phil294

    22 de agosto de 2018 a las 12:34

  • Comprender por qué sucede algo ayuda a resolver el problema. Ambas respuestas son buenas, una entra en pequeños detalles mientras que la otra da una visión general. Se complementan entre sí.

    –Tinus Tate

    6 de noviembre de 2018 a las 19:18


Puede usar -XX:+UseSerialGC como argumento JVM para especificar Serial Garbage Collector cuál es la mejor opción para reducir Memory Heap.

¿Ha sido útil esta solución?