Optimización de parámetros de JVM (artículos básicos)

En los últimos días, probé el entorno de preproducción y descubrí que TPS era inestable. Debido a que es un sistema refactorizado, se dice que el sistema original no tiene problemas cuando tiene alta concurrencia, como resultado, el sistema refactorizado es todo tipo de inestable cuando es presionado por decenas de concurrentes. Aunque el colega de la prueba no dijo nada, sintió que le habían abofeteado. . .

Por lo tanto, lo primero que me viene a la mente para varias investigaciones son los parámetros de la JVM, por lo que la optimicé con la esperanza de producir un buen resultado. Aunque más tarde se demostró que el motivo de la inestabilidad fue la inestabilidad del servidor de pruebas de estrés donde se instaló LoadRunner, que no está relacionado con mi sistema, pero también es un registro. Uno es hacer una copia de seguridad, y el otro es ser un referente para los demás.

Palabras escritas en el frente

Debido a que los valores predeterminados de los parámetros proporcionados por Hotspot JDK cambian constantemente entre versiones menores, los parámetros también se afectarán entre sí. Además, diferentes configuraciones de servidor pueden afectar el resultado final. Por lo tanto, no sea supersticioso acerca de la configuración de parámetros en un artículo determinado en Internet (incluido este). Todas las configuraciones deben ser probadas por usted mismo antes de que puedan usarse. En vista del cambio constante de los valores predeterminados de los parámetros de la JVM, puede utilizar para -XX:+PrintFlagsFinalimprimir los valores predeterminados de los parámetros de la JVM del entorno actual, como: java -XX:PrintFlagsFinal -versiono puede utilizar para java [生产环境参数] -XX:+PrintFlagsFinal –version | grep [待查证的参数]ver datos de parámetros específicos.

Estos son los parámetros de un servidor 8G, la información de la versión de JDK es la siguiente:

java version "1.8.0_73"
Java(TM) SE Runtime Environment (build 1.8.0_73-b02)
Java HotSpot(TM) 64-Bit Server VM (build 25.73-b02, mixed mode)

Configuración de montón

La configuración de la memoria de pila debe considerarse como la cualidad básica de un programador de Java, y al menos los tres parámetros de Xms, Xmx y Xmn deben modificarse. Pero, ¿cuánta memoria podría ocupar una JVM con un tamaño de pila 2G en total?

Memoria de montón + número de subprocesos * pila de subprocesos + generación permanente + código binario + memoria fuera del montón

2G + 1000 * 1M + 256M + 48 / 240M + (~ 2G) = 5.5G (3.5G) -Memoria de pila
: almacena objetos Java, el valor predeterminado es 1/64 de memoria física
-Pila de subprocesos: almacena variables locales (tipo atómico , Referencia) y otros, el valor predeterminado es 1M
-generación permanente: definición de clase de almacenamiento y grupo constante, preste atención a la diferencia entre JDK7 / 8
-código binario: JDK7 y 8, el valor predeterminado al abrir la compilación multicapa es diferente, de 48 a 240M
-Memoria externa de pila: utilizada por Netty, caché fuera de pila, etc. El máximo predeterminado es aproximadamente el tamaño de la memoria de pila

En otras palabras, si la memoria del montón se establece en 2G, la JVM con 1000 subprocesos puede necesitar ocupar 5,5 G. Teniendo en cuenta varias condiciones como la ocupación del sistema, la ocupación de IO, etc., un servidor 8G también iniciará un servicio. Por supuesto, si el número de subprocesos es pequeño, la concurrencia no es alta y la presión no es alta, aún puede iniciar más de uno y también puede reducir la memoria del montón.

  1. -Xms2g y -Xmx2g: tamaño de la memoria de pila, el primero es la memoria de pila mínima, el segundo es la memoria de pila máxima, el valor más adecuado es 2-4g y mayor es el tiempo de GC
  2. -Xmn1g o (-XX: NewSize = 1g y -XX: MaxNewSize = 1g) o -XX: NewRatio = 1: Establece el tamaño del Cenozoico, el JDK predetermina que el Cenozoico ocupa 1/3 del tamaño de la memoria del montón, es decir -XX:NewRatio=2. Aquí está el juego de 1g, eso es -XX:NewRatio=1. Puede configurarlo según sus necesidades.
  3. -XX: MetaspaceSize = 128m y -XX: MaxMetaspaceSize = 512m, la generación inmortal de JDK8 puede usar casi toda la memoria de la máquina. Para evitar que el servidor no pueda conectarse debido al uso excesivo de memoria, es necesario establezca un valor inicial de 128M y un máximo de 512M Valor de protección.
  4. -XX: SurvivorRatio: El tamaño de cada área de supervivencia en el Cenozoico, el valor predeterminado es 8, que es 1/10 del Cenozoico, 1 / (SurvivorRatio + 2). A algunas personas les gusta establecer pequeños puntos para el Cenozoico, pero evitan demasiado El pequeño tamaño hace que sea imposible poner objetos temporales en el área de supervivencia y querer ser promovido a la generación anterior.Todavía es del GC Log para ver la situación real.
  5. -Xss256k: fuera del montón, los subprocesos ocupan la memoria de la pila y cada subproceso es de 1 M de forma predeterminada. Almacene la pila de llamadas a métodos, variables locales, variables locales después del reemplazo escalar, etc. A algunas personas les gusta establecer pequeños puntos para ahorrar memoria y abrir más subprocesos. Pero de todos modos, si la memoria es suficiente, no es necesario establecer un tamaño pequeño.A algunas personas les gusta establecer un tamaño más grande, especialmente cuando hay llamadas recursivas como el análisis JSON.
  6. -XX: MaxDirectMemorySize: El tamaño de la memoria fuera del montón / memoria directa, el valor predeterminado es el tamaño de la memoria del montón menos un área de Superviviente.
  7. -XX: ReservedCodeCacheSize: El área de almacenamiento del código binario después de la compilación JIT. Cuando está lleno, no se compilará. Por defecto, la compilación multicapa es 240 M. Puede comprobar el tamaño de CodeCache en JMX.

Configuración de GC

En la actualidad, los GC más convencionales son CMS y G1, y algunos grandes dioses sugieren usar 8G como límite. (Se dice que JDK 9 tiene como valor predeterminado G1). Debido a que la memoria establecida por la aplicación es relativamente pequeña, se selecciona el recopilador CMS. Los siguientes parámetros también son para el colector CMS Si es necesario, agregue los parámetros del colector G1 después de esperar.

Configuración de CMS

  1. -XX: + UseConcMarkSweepGC: habilita el recolector de basura CMS
  2. -XX: CMSInitiatingOccupancyFraction = 80 y -XX: + UseCMSInitiatingOccupancyOnly: Los dos parámetros deben usarse juntos; de lo contrario, el 75 del primer parámetro es solo un valor de referencia y la JVM volverá a calcular el tiempo de GC.
  3. -XX: MaxTenuringThreshold = 15: Cuántas veces el objeto ha sobrevivido al Young GC en el área de Survivor y luego ha ascendido a la generación anterior. El valor predeterminado es 15. Young GC es la mayor fuente de pausas de aplicaciones, y la cantidad de objetos supervivientes después de GC en la nueva generación afecta directamente el tiempo de pausa, por lo que si conoce la frecuencia de ejecución de Young GC y el ciclo de vida más largo de la mayoría de los objetos temporales en la aplicación , puedes usarlo Hazlo más corto, para que los objetos a largo plazo de la nueva generación que no son objetos temporales puedan promoverse rápidamente a la generación anterior.
  4. -XX: -DisableExplicitGC: Permitir usar System.gc () para llamar activamente a GC. Debe explicarse aquí que algunas sugerencias de optimización de JVM son establecer -XX: -DisableExplicitGC y desactivar la llamada manual a System.gc (). Esto se debe a que System.gc () activa la GC completa y la GC completa frecuente afectará seriamente al rendimiento. Sin embargo, muchos marcos NIO, como Netty, utilizan memoria fuera del montón. Si no hay un GC completo, no se puede recuperar la memoria fuera del montón. Si no llama activamente a System.gc (), debe esperar hasta que la propia JVM active Full GC. En este momento, puede causar una pausa larga (STW) y la carga de la máquina aumentará. Por lo tanto, System.gc () no se puede prohibir por completo y se debe acortar el tiempo de Full GC. Luego, use la opción -XX:+ExplicitGCInvokesConcurrento -XX:+ExplicitGCInvokesConcurrentAndUnloadsClassesy use el recopilador CMS para activar Full GC. Estas dos opciones deben -XX:+UseConcMarkSweepGCusarse juntas.
  5. -XX: + ExplicitGCInvokesConcurrent: Use System.gc () para activar CMS GC en lugar de Full GC. No está habilitado de forma predeterminada. Esta opción solo se puede habilitar cuando se usa la opción -XX: + UseConcMarkSweepGC.
  6. -XX: + ExplicitGCInvokesConcurrentAndUnloadsClasses: Cuando se usa System.gc (), la generación permanente también se incluye en el alcance de CMS. Esta opción solo se puede activar cuando se usa la opción -XX: + UseConcMarkSweepGC.
  7. -XX: + ParallelRefProcEnabled: el valor predeterminado es falso. Los objetos de referencia como WeakReference se procesan en paralelo. A menos que aparezca un registro con un tiempo de procesamiento de referencia largo en el registro de GC, el efecto no será obvio.
  8. -XX: + ScavengeBeforeFullGC: Realice Young GC una vez antes de que se ejecute Full GC.
  9. -XX: + UseGCOverheadLimit: Limita el tiempo de ejecución de GC. Si GC tarda demasiado, lanza OOM.
  10. -XX: + UseParallelGC: establece el recolector de basura paralelo
  11. -XX: + UseParallelOldGC: configura la generación anterior para usar el recolector de basura paralelo
  12. -XX: -UseSerialGC: apaga el recolector de basura en serie
  13. -XX: + CMSParallelInitialMarkEnabled y -XX: + CMSParallelRemarkEnabled: reduce la pausa de la marca
  14. -XX: + CMSScavengeBeforeRemark: el valor predeterminado es desactivado. Antes del comentario de CMS, realice un GC menor para borrar la nueva generación, de modo que el número de objetos de nueva generación referenciados desde los objetos de la generación anterior sea menor y detenga CMS en todo el mundo La fase de observación es más corta. Si ve que la fase de comentarios en el registro de GC tarda demasiado, puede activar este elemento para ver si tiene algún efecto. De lo contrario, no lo active. Habrá más YGC en vano.
  15. -XX: CMSWaitDuration = 10000: establece el intervalo máximo de recolección de basura, el valor predeterminado es 2000.
  16. -XX: + CMSClassUnloadingEnabled: Limpia la clase caducada en la generación permanente en CMS sin esperar a Full GC. JDK7 está cerrado por defecto y JDK8 está abierto. Depende de su propia situación, por ejemplo, si ejecuta scripts de lenguaje dinámico como Groovy para generar una gran cantidad de clases temporales. Aumentará el tiempo de pausa del comentario de CMS, por lo que si las nuevas clases no se cargan con frecuencia, este parámetro aún no está abierto.

Registro de GC

El proceso de GC puede proporcionar una base de optimización a través del registro de GC.

  1. -XX: + PrintGCDetails: Habilita la función de impresión de registros de gc
  2. -Xloggc: /path/to/gc.log: especifique la ubicación del registro de gc
  3. -XX: + PrintHeapAtGC: Imprime información detallada de la pila antes y después de GC
  4. -XX: + PrintGCDateStamps: imprime una fecha legible en lugar de una marca de tiempo
  5. -XX: + PrintGCApplicationStoppedTime: Imprime todos los tiempos de pausa de JVM, si realmente encuentra algunas pausas desconocidas, agregue temporalmente -XX:+PrintSafepointStatistics -XX: PrintSafepointStatisticsCount=1para encontrar el motivo.
  6. -XX: + PrintGCApplicationConcurrentTime: Imprime el tiempo de ejecución normal de la JVM entre dos pausas, y el -XX:+PrintGCApplicationStoppedTimeefecto es mejor cuando se usan juntas.
  7. -XX: + PrintTenuringDistribution: vea el umbral del nuevo período de supervivencia después de cada GC menor
  8. -XX: + UseGCLogFileRotation y -XX: NumberOfGCLogFiles = 10 y -XX: GCLogFileSize = 10M: El registro de GC se borrará después de reiniciar, pero si una aplicación no se reinicia durante mucho tiempo, el registro de GC aumentará, así que agregue estos 3 parámetros, es el registro de GC que se escribe en el archivo de manera continua, pero si se reinicia, el nombre puede resultar confuso.
  9. -XX: PrintFLSStatistics = 1: Imprimir estadísticas sobre la fragmentación de la memoria antes y después de cada GC

Otros ajustes de parámetros

  1. -ea: Habilite la aserción, no hay nada que decir al respecto, puede optar por habilitarla o puede optar por no habilitarla, no hay gran diferencia. Se procesa completamente de acuerdo con su propio sistema.
  2. -XX: + UseThreadPriorities: Habilita la prioridad de subprocesos, principalmente porque podemos dar menor prioridad a las tareas periódicas para evitar interferir con el trabajo del cliente. En mi entorno actual, está habilitado de forma predeterminada.
  3. -XX: ThreadPriorityPolicy = 42: Permitir que se reduzca la prioridad de subprocesos
  4. -XX: + HeapDumpOnOutOfMemoryError: se realiza un volcado de almacenamiento cuando se produce un desbordamiento de memoria
  5. -XX: HeapDumpPath = / path / to / java_pid.hprof: este parámetro funciona junto con el -XX:+HeapDumpOnOutOfMemoryErrorarchivo de salida cuando se configura el heap-dump.
  6. -XX: ErrorFile = / ruta / a / hs_err_pid.log: especifique la ubicación del registro de errores fatales. Generalmente, cuando ocurre un error fatal en la JVM, se generará un archivo similar a hs_err_pid.log. El valor predeterminado está en el directorio de trabajo (si no tiene permiso, intentará crearlo en / tmp), pero Es mejor especificar la ubicación usted mismo, que es más fácil de recopilar y encontrar. Evite pérdidas.
  7. -XX: StringTableSize = 1000003: Especifique el tamaño del grupo constante de cadenas, el valor predeterminado es 60013. Aquellos con un poco de sentido común de Java deben saber que las cadenas son constantes y no se pueden modificar después de que se crean. El lugar donde se encuentran estas constantes se llama el conjunto de constantes de cadena. Si hay muchas operaciones de cadena en su sistema, y ​​estos valores de cadena son relativamente fijos, puede aumentar adecuadamente el tamaño del grupo si está permitido.
  8. -XX: + AlwaysPreTouch: Toda la memoria definida por todos los parámetros se cargan al inicio. El uso de este parámetro puede hacer que el inicio sea más lento, pero será más rápido en el proceso de uso de memoria posterior. Puede garantizar la asignación continua de páginas de memoria, y la nueva generación no hará que el GC se detenga ni se extienda debido a la aplicación de páginas de memoria cuando se promueva la nueva generación. Por lo general, solo se sentirá cuando la memoria sea superior a 32G.
  9. -XX: -UseBiasedLocking: deshabilita bloqueos sesgados (deshabilitar bloqueos sesgados puede traer cierta optimización del rendimiento en un entorno donde se crea una gran cantidad de objetos de bloqueo y son altamente concurrentes (es decir, aplicaciones no multiproceso y altamente concurrentes))
  10. -XX: AutoBoxCacheMax = 20000: Aumenta el rango de boxeo automático de objetos digitales. JDK por defecto -128 a 127 int y long. Los objetos se crearán inmediatamente si se excede el rango. Por lo tanto, aumentar el rango puede mejorar el rendimiento, pero también requiere pruebas.
  11. -XX: -OmitStackTraceInFastThrow: No ignore la pila de excepciones repetidas. Esta es una optimización del JDK. Una gran cantidad de excepciones JDK repetidas ya no imprimirán su StackTrace. Pero si el sistema es un sistema que no se reinicia durante mucho tiempo y ejecuta N múltiples excepciones en el mismo lugar, el JDK ignora el resultado. ¿No es así porque no puede ver el StackTrace específico cuando ver el registro, entonces, ¿cómo se depura? Es mejor cerrarlo.
  12. -XX: + PerfDisableSharedMem: habilita el uso de memoria estándar. El control de JVM se divide en memoria estándar o compartida. La diferencia es que uno está en la memoria de JVM, el otro es para generar archivos / tmp / hsperfdata_ {userid} / {pid}, almacenar estadísticas y mapear a la memoria a través de mmap, y otros Los procesos pueden pasar contenido de acceso a archivos. Con este parámetro, puede prohibir que la JVM escriba datos estadísticos en el archivo. El precio es que los comandos jps y jstat ya no están disponibles y los datos solo se pueden obtener a través de jmx. Pero en la resolución de problemas, las herramientas pequeñas como jps y jstat son muy fáciles de usar y mucho más fáciles de usar que las cosas pesadas como jmx, por lo que debe tomar sus propias decisiones. A continuación, se muestra un ejemplo de pausa de GC.
  13. -Djava.net.preferIPv4Stack = true: este parámetro es un parámetro que pertenece a problemas de red y se puede configurar según sea necesario. En algunas máquinas con ipv6 habilitado, el InetAddress.getLocalHost().getHostName()nombre completo de la máquina se puede obtener a través de , pero en las máquinas ipv4, el nombre de la máquina obtenido por este método puede estar incompleto y el nombre completo de la máquina se puede obtener a través de este parámetro.

El ejemplo dado por el gran dios

El ejemplo dado por el Gran Dios se publica a continuación, puede consultarlo, pero se recomienda usarlo después de una verificación específica en su propio entorno.Después de todo, el entorno del Gran Dios sigue siendo diferente de su propio entorno.

Relacionado con el rendimiento

-XX: -UseBiasedLocking -XX: -UseCounterDecay -XX: AutoBoxCacheMax = 20000
-XX: + PerfDisableSharedMem (可选) -XX: + AlwaysPreTouch -Djava.security.egd = archivo: / dev /./ urandom

Relacionado con el tamaño de la memoria (JDK7)

-Xms4096m -Xmx4096m -Xmn2048m -XX: MaxDirectMemorySize = 4096m
-XX: PermSize = 128m -XX: MaxPermSize = 512m -XX: ReservedCodeCacheSize = 240M

Si usa jdk8, reemplace -XX: PermSize = 128m -XX: MaxPermSize = 512m con -XX: MetaspaceSize = 128m -XX: MaxMetaspaceSize = 512m. Como se mencionó anteriormente, estos dos conjuntos de parámetros son para garantizar la seguridad. Aún así, se recomienda agregar.

Relacionados con CMS GC

-XX: + UseConcMarkSweepGC -XX: CMSInitiatingOccupancyFraction = 75
-XX: + UseCMSInitiatingOccupancyOnly -XX: MaxTenuringThreshold = 6
-XX: + ExplicitGCInvokesConcurrent -XX: + ParallelRefProcEnabled

Relacionado con el registro de GC

-Xloggc: /dev/shm/app-gc.log -XX: + PrintGCApplicationStoppedTime
-XX: + PrintGCDateStamps -XX: + PrintGCDetails

Relacionado con el registro de excepciones

-XX: -OmitStackTraceInFastThrow -XX: ErrorFile = $ {LOGDIR} /hs_err_%p.log
-XX: + HeapDumpOnOutOfMemoryError -XX: HeapDumpPath = $ {LOGDIR} /

Relacionado con JMX

-Dcom.sun.management.jmxremote.port = $ {JMX_PORT} -Dcom.sun.management.jmxremote
-Djava.rmi.server.hostname = 127.0.0.1 -Dcom.sun.management.jmxremote.authenticate = false
-Dcom. sun.management.jmxremote.ssl = false

Articulo de referencia

  1. Guía de optimización del rendimiento de Java versión 1.8, y el combate real de Vipshop
  2. Análisis de escape y asignación de objetos TLAB y Java en Java
  3. El error de cuatro meses: las estadísticas de JVM provocan pausas en la recolección de basura

Página de inicio personal: http://www.howardliu.cn

Publicación de blog personal: optimización de parámetros de JVM (artículos básicos)

Página de inicio de CSDN: http://blog.csdn.net/liuxinghao

Publicación de blog de CSDN: optimización de parámetros de JVM (artículos básicos)

Supongo que te gusta

Origin blog.csdn.net/conansix/article/details/73963399
Recomendado
Clasificación