Ubicación del problema en línea ------ cuello de botella de memoria

El problema de la memoria es más problemático que el de la CPU y hay más escenarios. Incluye principalmente OOM, problemas de GC y memoria fuera del montón. En términos generales, primero usaremos el comando libre para verificar las diversas condiciones de la memoria de un disparo.

gratis

freeEs para ver el uso de la memoria, incluida la memoria física, la memoria de intercambio (swap) y la memoria intermedia del kernel.

free -h -s 3Indica que el estado de la memoria se emite cada tres segundos, el comando es el siguiente

[1014154@cc69dd4c5-4tdb5 ~]$ free
              total        used        free      shared  buff/cache   available
Mem:      119623656    43052220    45611364     4313760    30960072    70574408
Swap:             0           0           0
[1014154@cc69dd4c5-4tdb5 ~]$ free -h -s 3
              total        used        free      shared  buff/cache   available
Mem:           114G         41G         43G        4.1G         29G         67G
Swap:            0B          0B          0B

              total        used        free      shared  buff/cache   available
Mem:           114G         41G         43G        4.1G         29G         67G
Swap:            0B          0B          0B
  • Mem: Es el uso de la memoria.

  • Swap: Es el uso del espacio de intercambio.

  • total: La memoria física total disponible y el espacio de intercambio del sistema.

  • used: Memoria física y espacio de intercambio que se ha utilizado.

  • free: La cantidad de memoria física y espacio de intercambio disponible para su uso es la cantidad de memoria física que aún no se ha usado  .

  • shared: El tamaño de la memoria física que se comparte.

  • buff/cache: El tamaño de la memoria física utilizada por el búfer y la caché.

  • available: El tamaño de la memoria física que también puede utilizar la aplicación Es la cantidad de memoria disponible desde la perspectiva de la aplicación, disponible ≈ libre + búfer + caché  .

Espacio de intercambio

El espacio de intercambio es un área en el disco. Cuando la memoria física del sistema es escasa, Linux guardará los datos a los que rara vez se accede en la memoria para intercambiar, de modo que el sistema tenga más memoria física para atender cada proceso y cuando el sistema lo necesite para acceder Cuando se carga el contenido almacenado en el intercambio, los datos del intercambio se cargan en la memoria, lo que a menudo se denomina intercambio e intercambio. El espacio de intercambio puede aliviar la falta de memoria hasta cierto punto, pero necesita leer y escribir datos de disco, por lo que el rendimiento no es muy alto.

vmstat (recomendado)

Vmstat (VirtualMeomoryStatistics, estadísticas de memoria virtual) es una herramienta común para monitorear la memoria en Linux. Puede monitorear la situación general de la memoria virtual, proceso, CPU, etc. del sistema operativo. Se recomienda.

vmstat 5 3Significa que las estadísticas se cuentan cada 5 segundos, un total de tres conteos.

[1014154@cc69dd4c5-4tdb5 ~]$ vmstat 5 3
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 8  0      0 45453212 374768 30763728    0    0    14    99    1    1 11 10 78  0  1
10  0      0 45489232 374768 30763360    0    0     2  1275 95118 97908 13 11 75  0  1
 6  0      0 45452908 374768 30765148    0    0     0  3996 89924 92073 12 10 78  0  1

procs

r: Representa el número de procesos en ejecución y en espera del intervalo de tiempo de la CPU (es decir, cuántos procesos están realmente asignados a la CPU). Si este valor es mayor que el número de CPU del sistema durante mucho tiempo, significa que la CPU es insuficiente y es necesario aumentar la CPU  . b: Indica el número de procesos que esperan recursos, como esperar E / S o intercambio de memoria.

memoria

swpd: Indica el tamaño de la memoria del conmutador al área de intercambio de memoria, es decir, el tamaño utilizado de la memoria virtual (en KB). Si es mayor que 0, significa que la memoria física de su máquina es insuficiente. Si no es la causa de la pérdida de memoria del programa, debe actualizar la memoria o migrar las tareas que consumen memoria a otras máquinas  . free: Indica la memoria física actualmente libre. buff: Indica el tamaño del búfer. Generalmente, se requiere almacenamiento en búfer para leer y escribir en dispositivos de bloque  Cache: indica el tamaño del caché, que generalmente se utiliza como un sistema de archivos para almacenar en búfer. Los archivos a los que se accede con frecuencia se almacenarán en caché. Si el valor de caché es muy grande, significa que hay más archivos en caché. El bi-in es relativamente pequeño, lo que indica que la eficiencia del sistema de archivos es mejor.

intercambio

si: Indica que los datos se leen del disco a la memoria; en términos sencillos, es el tamaño de la memoria virtual leída del disco por segundo. Si este valor es mayor que 0, significa que la memoria física no es suficiente o se filtra la memoria Es necesario encontrar el proceso que consume memoria para solucionarlo  . so: Representa el tamaño de los datos escritos desde la memoria al disco, es decir, los datos que ingresan a la memoria desde el área de intercambio de memoria.

Nota: En circunstancias normales, los valores de si y so son ambos 0. Si los valores de si y so no son 0 durante mucho tiempo, significa que la memoria del sistema es insuficiente y la memoria del sistema debe ser aumentado.

I

bi: Indica la cantidad total de datos leídos por el dispositivo de bloque, es decir, disco leído, en kb / s  bo: Indica la cantidad total de datos escritos en el dispositivo de bloque, es decir, disco de escritura, en kb / s

Nota: Si el valor de bi + bo es demasiado grande y el valor de wa es demasiado grande, indica el cuello de botella de E / S del disco del sistema.

sistema

in: Indica el número de terminales de dispositivo observados por segundo en un intervalo de tiempo determinado. cs: Representa la cantidad de cambios de contexto por segundo. Este valor debe ser lo más pequeño posible. Si es demasiado grande, considere la posibilidad de reducir la cantidad de subprocesos o procesos  . Por ejemplo, en servidores web como apache y nginx, generalmente realizamos una prueba de rendimiento de miles o incluso decenas de miles de pruebas simultáneas. El proceso de selección de un servidor web se puede ajustar por el valor máximo del proceso o subproceso, y la prueba de presión es hasta que el cs alcanza un valor relativamente pequeño, el número de procesos y subprocesos es un valor más apropiado. Lo mismo ocurre con las llamadas al sistema.Cada vez que se llama a una función del sistema, nuestro código ingresará al espacio del kernel, lo que provocará un cambio de contexto.Esto requiere muchos recursos y debemos tratar de evitar llamar a las funciones del sistema con frecuencia. Demasiados cambios de contexto significa que la mayor parte de su CPU se desperdicia en el cambio de contexto, lo que resulta en menos tiempo para que la CPU haga cosas serias y la CPU no se utiliza por completo, lo cual no es deseable.

Nota: Cuanto mayores sean estos dos valores, más CPU consumirá el kernel.

UPC

us: Indica el porcentaje de tiempo de CPU consumido por el proceso de usuario . Cuanto mayor sea el valor us, más tiempo de CPU consume el proceso de usuario. Si es superior al 50% durante un tiempo prolongado, debe considerar el programa o algoritmo de optimización  . sy: Indica el porcentaje de tiempo de CPU consumido por el proceso del kernel del sistema. Generalmente hablando, us + sy debe ser menor al 80%. Si es mayor al 80%, indica que puede haber un cuello de botella en la CPU  . id: Representa el porcentaje de tiempo que la CPU está en estado de espacio. wa: Representa el porcentaje de tiempo de CPU ocupado por IP en espera. Cuanto mayor es el valor de wa, más grave es la espera de E / S. Según la experiencia, el valor de referencia de wa es del 20%. Si supera el 20%, significa que la espera de E / S es grave y causa E / S. El motivo de la espera puede deberse a un gran número de lecturas y escrituras aleatorias en el disco, o al cuello de botella de préstamo (principalmente operación de bloque) del disco o del monitor  .

sar

sar y free son similares a sar -r 3la información de la memoria de salida cada tres segundos:

[root@localhost ~]# sar -r 3
Linux 3.10.0-1062.el7.x86_64 (localhost.localdomain)    2020年04月28日  _x86_64_        (2 CPU)

15时40分10秒 kbmemfree kbmemused  %memused kbbuffers  kbcached  kbcommit   %commit  kbactive   kbinact   kbdirty
15时40分13秒    106800   1314960     92.49      2144    573248   4110864    116.82    563664    498888        36
15时40分16秒    106816   1314944     92.49      2144    573248   4110864    116.82    563668    498888        36
15时40分19秒    106816   1314944     92.49      2144    573248   4110864    116.82    563668    4988

Memoria en montón

La mayoría de los problemas de memoria siguen siendo problemas de memoria acumulada. En la superficie, se divide principalmente en OOM y StackOverflow.

1 、 TÍO

Memoria insuficiente en JMV, OOM se puede dividir aproximadamente en los siguientes tipos:

  • Excepción en el hilo "principal" java.lang.OutOfMemoryError: no se puede crear un nuevo hilo nativo

Esto significa que no hay suficiente espacio de memoria para asignar la pila de Java al subproceso. Básicamente, todavía hay un problema con el código del grupo de subprocesos, como olvidar cerrar, por lo que primero debemos buscar el problema desde el nivel de código. , usando jstack o jmap. Si todo es normal, la JVM puede reducir el tamaño de una sola pila de subprocesos especificando Xss. Además, a nivel del sistema, puede aumentar el límite de subprocesos del sistema operativo modificando /etc/security/limits.confnofile y nproc;

imagen

  • Excepción en el hilo "principal" java.lang.OutOfMemoryError: espacio de almacenamiento dinámico de Java

Esto significa que el uso de memoria del montón ha alcanzado el valor máximo establecido por -Xmx, que debería ser el error OOM más común. La solución sigue siendo encontrarlo primero en el código. Si hay una pérdida de memoria, use jstack y jmap para localizar el problema. Si todo es normal, necesita ajustar el valor de Xmx para expandir la memoria;

  • Causado por: java.lang.OutOfMemoryError: Meta espacio

Esto significa que el uso de memoria del área de metadatos ha alcanzado el valor máximo establecido por XX: MaxMetaspaceSize. La idea de solución de problemas es la misma que la anterior. Los parámetros se pueden ajustar a través de XX: MaxPermSize (sin mencionar la generación permanente antes de 1.8) ;

2, desbordamiento de pila

La memoria de la pila se desborda y todos ven más de esto.

Excepción en el hilo "principal" java.lang.StackOverflowError

Indica que la memoria requerida por la pila de subprocesos es mayor que el valor de Xss, y también se verifica primero Los parámetros se ajustan a través de Xss, pero si el ajuste es demasiado grande, puede causar OOM.

3. Utilice JMAP para localizar fugas de memoria de código

Para la investigación de código anterior en OOM y StackOverflow, generalmente usamos JMAPjmap -dump: format = b, file = filename pid para exportar el archivo de volcado

imagen

Utilice mat (Herramientas de análisis de memoria de Eclipse) para importar archivos de volcado para su análisis. Generalmente, podemos seleccionar directamente Leak Suspects para fugas de memoria. Mat da sugerencias sobre fugas de memoria. También puede elegir Principales consumidores para ver el informe de objetos más grande. Las preguntas relacionadas con los hilos se pueden analizar seleccionando la descripción general del hilo. Además, elija la descripción general de la clase Histograma para analizar lentamente por sí mismo. Puede buscar tutoriales relacionados en el tapete.

imagen

En el desarrollo diario, las fugas de memoria en el código son relativamente comunes y están relativamente ocultas, lo que requiere que los desarrolladores presten más atención a los detalles. Por ejemplo, cada solicitud es un objeto nuevo, lo que da como resultado una gran cantidad de creación de objetos repetidos; operaciones de flujo de archivos pero no cerradas correctamente; activación manual incorrecta de gc; asignación de caché ByteBuffer irrazonable, etc.

Por otro lado, podemos especificar -XX: + HeapDumpOnOutOfMemoryError en los parámetros de inicio para guardar el archivo de volcado en OOM.

4. Temas e hilos de GC

El problema de gc no solo afecta a la CPU sino que también afecta a la memoria, las ideas para la solución de problemas también son las mismas. Generalmente, use jstat primero para verificar los cambios generacionales, como si el número de youngGC o fullGC es demasiado; si el aumento de indicadores como EU y OU es anormal, etc.

Si hay demasiados subprocesos y el gc no está a tiempo, también causará oom, la mayoría de los cuales son los mencionados anteriormente "no se puede crear un nuevo subproceso nativo". Además del análisis detallado del archivo de volcado por jstack, generalmente miramos primero el hilo general, a través de pstreee -p pid | wc -l.

imagen

O puede ver directamente el número de / proc / pid / task como el número de subprocesos.

imagen

Memoria fuera del montón

Si encuentra un desbordamiento de memoria sin pila, sería realmente desafortunado. En primer lugar, el rendimiento del desbordamiento de la memoria fuera del montón es el rápido crecimiento de la memoria física residente. Si se informa un error, el método de uso es incierto. Si se debe al uso de Netty, puede aparecer un error OutOfDirectMemoryError en el registro de errores Si es DirectByteBuffer directamente, informará OutOfMemoryError: memoria intermedia directa.

El desbordamiento de memoria fuera del montón a menudo está relacionado con el uso de NIO. Generalmente, primero usamos pmap para ver la memoria ocupada por el proceso pmap -x pid | sort -rn -k3 | head -30, esta sección significa ver los primeros 30 del pid correspondiente en orden inverso Gran segmento de memoria. Aquí puede ejecutar el comando nuevamente después de un tiempo para ver el crecimiento de la memoria, o dónde los segmentos de la memoria son sospechosos en comparación con las máquinas normales.

imagen

Si estamos seguros de que hay una terminal de memoria sospechosa, necesitamos analizar gdb a través de gdb --batch --pid {pid} -ex "dump memory filename.dump {dirección de inicio de memoria} {dirección de inicio de memoria + tamaño de bloque de memoria} "

imagen

Después de obtener el archivo de volcado, puede usar heaxdump para verlo hexdump -C filename | less, pero la mayor parte de lo que ve son caracteres binarios ilegibles.

NMT es una nueva función de HotSpot introducida por Java7U40. Con el comando jcmd, podemos ver la composición específica de la memoria. Es necesario agregar -XX: NativeMemoryTracking = resumen o -XX: NativeMemoryTracking = detalle a los parámetros de inicio, habrá una ligera pérdida de rendimiento.

Generalmente, para la situación en la que la memoria fuera del montón crece lentamente hasta que explota, se puede establecer primero una línea de base jcmd pid VM.native_memory.

imagen

Luego, espere un período de tiempo para ver el crecimiento de la memoria y haga un resumen o diferencia de nivel de detalle a través de jcmd pid VM.native_memory detail.diff (summary.diff).

imagen

imagen

Puede ver que la memoria analizada por jcmd es muy detallada, incluido el montón, el hilo y gc (por lo que las otras excepciones de memoria mencionadas anteriormente pueden ser analizadas por nmt). Aquí nos enfocamos en el crecimiento de la memoria interna, si el aumento es muy obvio. Si ese es el caso, hay un problema.

En el nivel de detalle, también habrá un crecimiento de segmentos de memoria específicos, como se muestra en la figura siguiente.

imagen

Además, a nivel del sistema, también podemos usar el comando strace para monitorear la asignación de memoria. Strace -f -e "brk, mmap, munmap" -p pid, la información de asignación de memoria aquí incluye principalmente pid y dirección de memoria.

imagen

Pero, de hecho, es difícil localizar el problema específico con las operaciones anteriores. La clave es mirar la pila de registro de errores, encontrar el objeto sospechoso, averiguar su mecanismo de recuperación y luego analizar el objeto correspondiente. Por ejemplo, si DirectByteBuffer asigna memoria, se requiere GC completo o system.gc manual para reciclarlo (por lo que es mejor no usar -XX: + DisableExplicitGC). De hecho, podemos rastrear la memoria del objeto DirectByteBuffer y activar manualmente fullGC a través de jmap -histo: live pid para ver si se ha recuperado la memoria fuera del montón. Si se recupera, existe una alta probabilidad de que la memoria fuera del montón se asigne demasiado pequeña, lo que se puede ajustar mediante -XX: MaxDirectMemorySize. Si no hay ningún cambio, utilice jmap para analizar los objetos que no pueden ser gc y la relación de referencia con DirectByteBuffer.

Problemas de GC

Las pérdidas de memoria en el montón siempre van acompañadas de excepciones de GC. Sin embargo, los problemas de GC no solo están relacionados con problemas de memoria, sino que también pueden causar una serie de complicaciones, como la carga de la CPU y los problemas de red. Solo están relativamente relacionados con la memoria, por lo que aquí resumiremos por separado los problemas relacionados con GC.

En el capítulo de la CPU, presentamos el uso de jstat para obtener la información actual del cambio generacional de GC. Más a menudo, usamos el registro de GC para solucionar problemas, agregando -verbose: gc -XX: + PrintGCDetails -XX: + PrintGCDateStamps -XX: + PrintGCTimeStamps a los parámetros de inicio para activar el registro de GC.

El significado de los registros comunes de Young GC y Full GC no se repetirá aquí.

Para el registro de gc, podemos inferir aproximadamente si youngGC y fullGC son demasiado frecuentes o demoran demasiado para prescribir el medicamento correcto. Analizaremos el recolector de basura G1 a continuación. También se recomienda que utilice G1-XX: + UseG1GC.

youngGC demasiado frecuente

Los youngGC frecuentes suelen ser objetos pequeños de período corto. Primero, considere si la configuración del área del Edén / Cenozoico es demasiado pequeña y vea si el problema se puede resolver ajustando las configuraciones de los parámetros como -Xmn y -XX: SurvivorRatio. Si los parámetros son normales, pero la frecuencia de gc joven aún es demasiado alta, debe usar Jmap y MAT para investigar más a fondo el archivo de volcado.

youngGC tarda demasiado

El problema del consumo excesivo de tiempo depende de qué parte del registro de GC requiera tiempo. Tomando el registro G1 como ejemplo, puede concentrarse en el escaneo de raíz, la copia de objeto, el proceso de referencia y otras etapas. Ref Proc lleva mucho tiempo, por lo que debemos prestar atención a las referencias a objetos relacionados. Root Scanning lleva mucho tiempo, por lo que debemos prestar atención a la cantidad de hilos y referencias de generación cruzada. Object Copy necesita prestar atención al ciclo de vida del objeto. Y el análisis que requiere mucho tiempo requiere una comparación horizontal, es decir, una comparación que requiere mucho tiempo con otros proyectos o períodos de tiempo normales. Por ejemplo, si el análisis de raíz en la figura aumenta más que el período de tiempo normal, significa que hay demasiados hilos.

imagen

Gatillo fullGC

G1 es más de MixedGC, pero mixedGC se puede investigar de la misma manera que youngGC. Cuando se activa fullGC, generalmente habrá problemas. G1 se degenerará y usará el recolector en serie para completar el trabajo de limpieza de basura. El tiempo de pausa llega al segundo nivel, que se puede decir que es medio arrodillado.

Las razones de fullGC pueden incluir lo siguiente, así como algunas ideas para el ajuste de parámetros:

  • Fallo de fase concurrente: En la fase de marcado concurrente, la generación anterior se llena antes de MixGC, luego G1 abandonará el ciclo de marcado en este momento. En este caso, es posible que deba aumentar el tamaño del montón o ajustar el número de subprocesos de marcado simultáneos-XX: ConcGCThreads;

  • Error de promoción: no hay suficiente memoria para el objeto de supervivencia / promoción durante la GC, por lo que se activa la GC completa. En este momento, puede aumentar el porcentaje de memoria reservada a través de -XX: G1ReservePercent, reducir -XX: InitiatingHeapOccupancyPercent para iniciar la marca por adelantado, y -XX: ConcGCThreads para aumentar el número de subprocesos marcados también es posible;

  • Error de asignación de objetos grandes: los objetos grandes no pueden encontrar un espacio de región adecuado para la asignación y se ejecutará fullGC. En este caso, puede aumentar la memoria o aumentar -XX: G1HeapRegionSize;

  • El programa ejecuta activamente System.gc (): no lo escriba de forma casual.

Además, podemos configurar -XX: HeapDumpPath = / xxx / dump.hprof en los parámetros de inicio para volcar archivos relacionados con fullGC, y usar jinfo para volcar antes y después de gc

jinfo -flag + HeapDumpBeforeFullGC pid 

jinfo -flag + HeapDumpAfterFullGC pid

De esta manera, se obtienen dos archivos de volcado Después de la comparación, el foco principal está en los objetos problemáticos lanzados por gc para localizar el problema.

 

 

Supongo que te gusta

Origin blog.csdn.net/weixin_42073629/article/details/115273090
Recomendado
Clasificación