Combate de coleccionistas de CMS
Las últimas preguntas de entrevistas reales para empresas de Internet de primera línea recopiladas en 2020 (todas organizadas en documentos), hay muchos productos secos, incluidas explicaciones detalladas de netty, primavera, hilo, nube de primavera, etc., también hay planes de aprendizaje detallados, preguntas de entrevista, etc. Siento que estoy en la entrevista Esta sección es muy clara: para obtener la información de la entrevista, simplemente: haga clic aquí para obtenerla !!! Contraseña: CSDN
Comienza el combate real, ¿estás listo?
Código de escenario empresarial simulado:
@RestController
public class IndexController {
/***
* 存 big 对象
* @return
*/
@GetMapping("/put")
public String process() {
ArrayList<User> users = queryUsers();
for (User user:users){
//TODO 业务操作
}
return "ok";
}
private ArrayList<User> queryUsers() {
ArrayList<User> users = new ArrayList<>();
for (int i = 0; i < 50000; i++) {
users.add(new User(i, "java2b"));
}
return users;
}
}
public class User {
private int id;
private String name;
private byte[] data;
public User(int id, String name) {
this.id = id;
this.name = name;
data=new byte[1 * 128 * 1024];
}
}
Información del colector de salida:
/***
* 打印 jvm 信息
* @return
*/
@GetMapping("/info")
public String info() {
List<GarbageCollectorMXBean> garbages = ManagementFactory.getGarbageCollectorMXBeans();
StringBuilder stringBuilder = new StringBuilder();
for (GarbageCollectorMXBean garbage : garbages) {
stringBuilder.append("垃圾收集器:名称=" + garbage.getName() + ",收集=" + garbage.getCollectionCount() + ",总花费时间="
+ garbage.getCollectionTime());
// + ",内存区名称=" + Arrays.deepToString(garbage.getMemoryPoolNames()));
stringBuilder.append("\r\n");
}
MemoryMXBean memory = ManagementFactory.getMemoryMXBean();
MemoryUsage headMemory = memory.getHeapMemoryUsage();
long MB = 1024 * 1024;
stringBuilder.append("head 堆:");
stringBuilder.append("\t 初始(M):" + headMemory.getInit() / MB);
stringBuilder.append("\t 最大(上限)(M):" + headMemory.getMax() / MB);
stringBuilder.append("\t 当前(已使用)(M):" + headMemory.getUsed() / MB);
stringBuilder.append("\t 提交的内存(已申请)(M):" + headMemory.getCommitted() / MB);
stringBuilder.append("\t 使用率:" + headMemory.getUsed() * 100 / headMemory.getCommitted() + "%");
return stringBuilder.toString();
}
Generando un paquete jar implementado en los
parámetros de inicio del servidor :
java -Xms256m -Xmx256m -verbose:gc -Xloggc:/root/jvm/gc-cms.log -XX:+UseConcMarkSweepGC -XX:+HeapDumpOnOutOfMemoryError -XX:+PrintHeapAtGC -XX:HeapDumpPath=/root/jvm/dump.hprof -XX:+PrintGCApplicationStoppedTime -XX:+PrintGCTimeStamps -XX:+PrintCommandLineFlags -XX:+PrintFlagsFinal -XX:+PrintGCDetails -XX:+UseCMSCompactAtFullCollection -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.port=6666 -Djava.rmi.server.hostname=192.168.0.31 -jar /root/jvm/jvm-web-0.0.1-SNAPSHOT.jar > catalina.out &
Aquí necesitamos insertar el significado de los parámetros de JVM.
Parámetros detallados de JVM:
Significado del parámetro JVM
-XX: -CMSPrecleaningEnabled
no realiza una limpieza previa. Aquellos que han pasado nuestros artículos anteriores saben que CMS tendrá un trabajo de limpieza previa durante el período de marcado y remarcado simultáneos, y esta pasada se intentará en 5 segundos. Espera a que llegue YGC. Para no perder mucho tiempo en la fase de re-marcado posterior para marcar la nueva generación de objetos.
-XX: + UseConcMarkSweepGC
Este parámetro iniciará el recopilador de CMS. La nueva generación predeterminada es ParNew, también puede configurar Serial como el colector de nueva generación. Este parámetro es equivalente a -Xconcgc.
-XX: ParallelGCThreads
es un procesador paralelo, por supuesto, también puede especificar el número de subprocesos. El número predeterminado de subprocesos simultáneos es: (ParallelGCThreads + 3) / 4).
-XX: ConcGCThreads
o -XX: ParallelCMSThreads; Además de la forma de configurar los subprocesos anterior, también puede configurar manualmente el número de subprocesos CMS concurrentes mediante cualquiera de estos dos parámetros
-XX: CMSInitiatingOccupancyFraction
Debido a que el recolector de CMS no es exclusivo, la aplicación aún funciona durante la recolección de basura, por lo que debe dejar suficiente memoria para la aplicación; de lo contrario, activará FGC. ¿Y cuándo funciona CMS GC? Se puede configurar mediante este parámetro, que representa el porcentaje de uso de memoria de la generación anterior. Cuando se alcanza este umbral, se ejecutará CMS. El valor predeterminado es 68. Si la memoria de la generación anterior crece rápidamente, se recomienda reducir el umbral para evitar FGC. Si el crecimiento es lento, puede aumentar el umbral para reducir el número de CMS GC. Mejore el rendimiento.
-XX: + UseCMSCompactAtFullCollection
Debido a que CMS usa un algoritmo de limpieza de marcas, no se puede evitar la fragmentación de la memoria. Este parámetro especifica una desfragmentación después de cada CMS.
-XX: CMSFullGCsBeforeCompaction Dado que cada desfragmentación afectará al rendimiento, puede usar este parámetro para establecer cuántas veces se desfragmentará CMS, que es la compresión de memoria.
-XX: + CMSClassUnloadingEnabled
permite el reciclaje de metadatos de clases.
-XX: CMSInitiatingPermOccupancyFraction
Cuando la tasa de ocupación del área permanente alcance este porcentaje, inicie el reciclaje de CMS (siempre que -XX: + CMSClassUnloadingEnabled esté activado).
-XX: UseCMSInitiatingOccupancyOnly
Indica que la recuperación de CMS solo se realiza cuando se alcanza el umbral.
XX: CMSWaitDuration = 2000
Debido a que la condición CMS GC es relativamente simple, la JVM tiene un subproceso para escanear el área Antigua con regularidad. El intervalo de tiempo se puede especificar mediante este parámetro (en milisegundos) y el valor predeterminado es 2s.
Parámetros de la herramienta JVM:
significado del parámetro JVM
-XX: + PrintGCDateStamps Imprime la marca de tiempo del registro del GC
-XX: + PrintGCDetails Imprime los detalles del GC
-XX: + PrintGCTimeStamps Imprime el tiempo que tarda la recolección de basura en comenzar a ejecutarse
-Xloggc: Salida de información de recolección de basura al archivo especificado
-verbose: gc Print GC log
-XX: + PrintGCApplicationStopedTime Ver el tiempo de suspensión de la aplicación causado por gc
XX: + PrintTenuringDistribution log de promoción de objetos
-XX: + HeapDumpOnOutOfMemoryError Archivo de volcado de salida cuando la memoria se desborda
Efecto de inicio:
acceso:
Request put: Veamos el efecto después de acceder al método put a través de http:
Durante la operación, encontramos que una gran cantidad de objetos entraron en la vejez, activaron el gc completo y cms se ha ido acumulando.
La tasa de utilización alcanzó el 99%, y cms no se detuvo ni un momento:
Análisis de registros
Versión de análisis de registro 1.0: extraemos un registro para analizar
[GC (Error de asignación) 0K-> 63K (64K), 0.0047147 segundos] 10258K-> 6780K (46144K), [Metaspace: 3434K-> 3434K (1056768K)], 0.0047613 segundos] [Tiempos: usuario = 0.02 sys = 0.00, real = 0.00 segundos] El registro tiene cuatro partes:
GC completo:
Indica que se ha realizado una recolección de basura. No hay una modificación completa al frente, lo que indica que se trata de un GC menor. Tenga en cuenta que no significa que solo la nueva generación es GC, y el STW existente será STW, ya sea la nueva generación o la generación anterior.
Error de asignación:
Muestra que la causa de GC esta vez es porque no hay suficiente espacio en la generación joven para almacenar nuevos datos.
10258K-> 6780K (46144K), la unidad es KB
Los tres parámetros son: la capacidad utilizada del área de memoria (en este caso, la generación joven) antes de GC, la capacidad utilizada del área de memoria después de GC y la capacidad total del área de memoria.
0.0047613 segundos:
Tiempo de GC empleado en esta área de memoria, en segundos
[Tiempos: usuario = 0.04 sys = 0.00, real = 0.01 segundos] :
Representar respectivamente el modo de usuario que consume mucho tiempo, el modo de kernel consume mucho tiempo y el tiempo total
Versión de Log Analysis 2.0:
Utilizando gceasy en línea para el análisis, abrimos el sitio web y cargamos los registros de gc que producimos, como se muestra en la figura:
Problemas de optimización: se enumeran 4 problemas que se pueden optimizar para el uso de memoria de metaespacio de nueva generación y generación anterior
Estadísticas de rendimiento: 97,39%
de los cambios de memoria de cada generación
El tiempo que consume el recolector de basura CMS en diferentes períodos
Clasificación y tiempo de aparición de GC
Problema de posicionamiento
Usamos los archivos de instantáneas producidos para localizar el problema:
JProfiler:
Descargado a la vista abierta local a través de JProfiler
View, los objetos grandes
encontramos que la colección ArrayList ocupa el 96% de la memoria, luego echamos un vistazo al fragmento de código que hace un uso intensivo de nuestra colección ArrayList
para encontrar los códigos correspondientes
por el código que encontramos método put Desbordamiento de memoria OOM causado por el uso extensivo de la colección ArrayList
para resumir
Creo que todo el mundo entiende el combate real anterior. El proceso general es:
1. Suficiente para simular el escenario real de usuarios de alto volumen del proyecto SpringBoot
2. Configure los parámetros de JVM y luego implemente los datos de supervisión en ejecución para generar archivos de registro.
3. Confirme el problema analizando el archivo de registro.
Los amigos que necesitan el código y el software anteriores, también tienen planes de estudio detallados, preguntas de la entrevista, etc. Siento que la entrevista es muy clara: para obtener solo la información de la entrevista: haga clic aquí para obtenerla !!! Contraseña: CSDN todos pueden hacerlo usted mismo Profundice la impresión en funcionamiento real.