Combate coletor CMS
As últimas perguntas da entrevista real para empresas de Internet de primeira linha coletadas em 2020 (todas organizadas em documentos), há muitos produtos secos, incluindo explicações detalhadas sobre netty, spring, thread, spring cloud, etc., também há planos de aprendizagem detalhados, perguntas de entrevista, etc. Sinto que estou na entrevista Esta seção é muito clara: para obter as informações da entrevista, basta: clicar aqui para obter !!! Senha: CSDN
O combate real começa, você está pronto?
Código de cenário de negócios 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];
}
}
Informações do coletor de saída:
/***
* 打印 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();
}
Gerando pacote jar implantado nos
parâmetros de inicialização do 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 &
Aqui, precisamos inserir o significado dos parâmetros JVM.
Parâmetros JVM detalhados:
Significado do parâmetro JVM
-XX: -CMSPrecleaningEnabled
não executa a pré-limpeza . Aqueles que passaram em nossos artigos anteriores sabem que o CMS terá um trabalho de pré-limpeza durante o período de marcação e remarcação simultâneas, e essa aprovação tentará em 5 segundos Espere o YGC chegar. Para não perder muito tempo na fase de remarcação posterior para marcar a nova geração de objetos.
-XX: + UseConcMarkSweepGC
Este parâmetro iniciará o coletor CMS. A nova geração padrão é ParNew, você também pode definir Serial como o coletor de nova geração. Este parâmetro é equivalente a -Xconcgc.
-XX: ParallelGCThreads
é um processador paralelo, é claro que você também pode especificar o número de threads. O número padrão de threads simultâneos é: (ParallelGCThreads + 3) / 4).
-XX: ConcGCThreads
ou -XX: ParallelCMSThreads; Além da maneira de definir threads acima, você também pode definir manualmente o número de threads CMS simultâneos por meio de qualquer um desses dois parâmetros
-XX: CMSInitiatingOccupancyFraction
Como o coletor CMS não é exclusivo, o aplicativo ainda está funcionando durante a coleta de lixo, portanto, é necessário deixar memória suficiente para o aplicativo, caso contrário, ele acionará o FGC. E quando o CMS GC é executado? Ele pode ser definido por este parâmetro, que representa a porcentagem de uso de memória da geração anterior. Quando esse limite for atingido, o CMS será executado. O padrão é 68. Se a memória da geração anterior crescer rapidamente, é recomendável diminuir o limite para evitar FGC. Se o crescimento for lento, você pode aumentar o limite para reduzir o número de GCs CMS. Melhore o rendimento.
-XX: + UseCMSCompactAtFullCollection
Como o CMS usa o algoritmo de limpeza de marcas, a fragmentação da memória não pode ser evitada. Este parâmetro especifica uma desfragmentação após cada CMS.
-XX: CMSFullGCsBeforeCompaction Como cada desfragmentação afetará o desempenho, você pode usar este parâmetro para definir quantas vezes o CMS será desfragmentado, que é a compactação da memória.
-XX: + CMSClassUnloadingEnabled
permite a reciclagem de metadados de classe.
-XX: CMSInitiatingPermOccupancyFraction
Quando a taxa de ocupação da área permanente atingir esse percentual, inicie a reciclagem do CMS (desde que -XX: + CMSClassUnloadingEnabled esteja ativado).
-XX: UseCMSInitiatingOccupancyOnly
Indica que a recuperação do CMS só é executada quando o limite é atingido.
XX: CMSWaitDuration = 2000
Como a condição CMS GC é relativamente simples, a JVM tem um encadeamento para varrer a área Antiga regularmente.O intervalo de tempo pode ser especificado por este parâmetro (em milissegundos) e o padrão é 2s.
Parâmetros da ferramenta JVM:
significado do parâmetro JVM
-XX: + PrintGCDateStamps Imprimir registro de data e hora do GC
-XX: + PrintGCDetails Imprimir detalhes do GC
-XX: + PrintGCTimeStamps Imprime o tempo que leva para a coleta de lixo começar a ser executada
-Xloggc: Saída de informações de coleta de lixo para o arquivo especificado
-verbose: gc Print GC log-
XX: + PrintGCApplicationStopedTime Exibir tempo de suspensão do aplicativo causado por gc
XX: + PrintTenuringDistribution log de promoção de
objeto- XX: + HeapDumpOnOutOfMemoryError Arquivo de despejo de saída quando a memória estourar
Efeito inicial:
Acesso:
Solicitação put: vamos ver o efeito após acessar o método put por meio de http:
Durante a operação, descobrimos que um grande número de objetos entrou na velhice, acionou o gc total e o cms foi coletando.
A taxa de utilização atingiu 99% e o cms não parou por um momento:
Análise de log
Log Analysis 1.0 version: Nós extraímos um log para analisar
[GC (falha de alocação) 0K-> 63K (64K), 0,0047147 s] 10258K-> 6780K (46144K), [Metaspace: 3434K-> 3434K (1056768K)], 0,0047613 s] [Vezes: usuário = 0,02 sys = 0,00, real = 0,00 segundos] O registro tem quatro partes:
GC Completo:
Indica que uma coleta de lixo foi realizada. Não há modificação Completa na frente, indicando que este é um GC Secundário. Observe que isso não significa que apenas a nova geração é GC e o STW existente será STW, seja a nova geração ou a antiga.
Falha de alocação:
Isso mostra que a causa do GC desta vez é porque não há espaço suficiente na geração jovem para armazenar novos dados.
10258K-> 6780K (46144K), a unidade é KB
Os três parâmetros são: a capacidade usada da área de memória (aqui, a geração jovem) antes do GC, a capacidade usada da área de memória após o GC e a capacidade total da área de memória.
0,0047613 s :
Tempo de GC gasto nesta área de memória, em segundos
[Vezes: usuário = 0,04 sys = 0,00, real = 0,01 segundos]:
Respectivamente representam o modo de usuário demorado, o modo kernel demorado e total
Versão do Log Analysis 2.0:
Usando gceasy online para análise, abrimos o site e carregamos os logs gc que produzimos, conforme mostrado na figura:
Problemas de otimização: 4 problemas que podem ser otimizados são listados para o uso de memória de meta-espaço da nova geração e da velha geração
Estatísticas de rendimento: 97,39%
das alterações de memória de cada geração
O tempo gasto pelo coletor de lixo CMS em diferentes períodos
Classificação e tempo de ocorrência de GC demorado
Problema de posicionamento
Usamos os arquivos de instantâneo produzidos para localizar o problema:
JProfiler:
Baixado para a visualização aberta local por meio do JProfiler
View, objetos grandes
que encontramos são a coleção ArrayList que ocupa 96% da memória, então damos uma olhada no pedaço de código que faz uso pesado de nossa coleção ArrayList
para encontrar os códigos correspondentes
pelo código que encontramos método put OOM de estouro de memória causado pelo uso extensivo da coleção ArrayList
Resumindo
Acredito que todos entendam o combate real acima. O processo geral é:
1. O suficiente para simular o cenário real de alto volume do usuário do projeto SpringBoot
2. Configure os parâmetros JVM e, em seguida, implemente os dados de monitoramento em execução para gerar arquivos de log
3. Confirme o problema analisando o arquivo de log.
Amigos que precisam do código e do software acima, também têm planos de estudo detalhados, perguntas de entrevista, etc. Acho que a entrevista é muito clara: para obter apenas as informações da entrevista: clique aqui para obtê-la !!! Senha: CSDN todos podem fazer você mesmo Aprofunde a impressão em operação real.