Uma cartilha rápida sobre o JVM Garbage Collector

Uma cartilha rápida sobre o JVM Garbage Collector


  1. Algoritmo para julgar objetos que podem ser reciclados
  • contagem de referência

    Adicione um contador de referência ao objeto. Quando o objeto é referenciado, o contador é incrementado em um e, quando a referência é inválida, o contador é decrementado em um. Objetos com um contador de 0 podem ser reciclados. A desvantagem do método de contagem de referência é que ele não pode lidar com referências circulares, e as referências circulares são muito comuns em Java, portanto, o coletor de lixo em Java geralmente não usa o método de contagem de referência.

  • análise de acessibilidade

    Por meio de uma série de objetos GC Roots, atravesse para baixo, marque todos os objetos que podem ser referenciados por GC Roots e os objetos não referenciados são considerados objetos de lixo e são reciclados.

    • Os objetos Raízes do GC incluem o seguinte:

      • Classe do sistema: classe do sistema

      • Native Stack: Objetos referenciados em JNI (Java Native Interface) na pilha de método local

      • Thread: O objeto de referência na pilha da máquina virtual (tabela de variáveis ​​locais no frame da pilha) do thread ativo

      • Monitor Ocupado: o objeto sendo bloqueado

      • Objetos referenciados por propriedades estáticas de classe na área de método

      • Objetos referenciados por constantes na área de método

    • quatro referências

      • Referência forte: o tipo de referência mais comum, se nenhum outro tipo de referência for explicitamente especificado, o padrão é usar uma referência forte. Referências fortes se aplicam a qualquer objeto em Java, incluindo strings, arrays, classes personalizadas e muito mais. Enquanto a referência forte existir, o objeto não será coletado como lixo, porque a própria referência forte é GC Roots.
String str = "Hello World!";

Neste exemplo, stra variável é uma referência de objeto que aponta para um objeto de string criado a partir de uma string literal. Esta é uma referência forte e, como é o tipo de referência padrão, ela não será recuperada pelo coletor de lixo nullaté que

  • Referências suaves: Objetos apontados por referências suaves não serão usados ​​como raízes de GC.Se o objeto tiver apenas referências suaves e nenhuma referência forte, ele será reciclado.
    Referências suaves podem ser criadas por meio SoftReferenceda classe .
SoftReference<String> softRef = new SoftReference<>("str");
String str = softRef.get();
  • Referências fracas: objetos apontados por referências fracas não serão usados ​​como raízes de GC. Quando o coletor de lixo verifica um objeto apontado apenas por referências fracas, ele recupera o objeto independentemente de haver memória suficiente ou de haver outras referências apontando para isso.
    Referências suaves podem ser criadas por meio WeakReferenceda classe .
WeakReference<String> weakRef = new WeakReference<>("str");
String str = weakRef.get();
  • Referência fantasma: A referência fantasma é o mais fraco de todos os tipos de referência, não pode ser usada sozinha, deve ser usada junto com a fila de referência, principalmente com ByteBuffer. Quando um objeto é referenciado por uma referência virtual, o coletor de lixo destruirá o objeto na próxima fase de recuperação e colocará o objeto de referência virtual correspondente ao objeto na fila de referência correspondente antes de destruir o objeto, para que o programa possa obtê-lo por pesquisando as mensagens da fila de referência para objetos destruídos por referências fantasmas.
    • Referência do finalizador: Uma subclasse de referência fantasma usada para rastrear se o objeto foi finalizado (Finalizado). Quando o objeto é recuperado pelo coletor de lixo, se seu método finalizador não tiver sido chamado, a referência do finalizador será adicionada a uma fila de referência global, aguardando que o encadeamento Finalizer chame o método finalizador do objeto. Como o agendamento da thread Finalizer é gerenciado pela própria JVM, o tempo de chamada do método finalizer é incerto, o que pode afetar o desempenho e a confiabilidade do programa.

Método finalizador finalize(): Em Java, cada objeto possui um método finalizador finalize(), que é chamado uma vez antes de o objeto ser recuperado pelo coletor de lixo. É usado principalmente para realizar algumas operações de limpeza antes que o objeto seja destruído, como fechar o arquivo , Liberar recursos , etc No entanto, existem alguns problemas com o método finalizador, como nenhuma garantia de tempo de execução, nenhuma maneira de evitar deadlock, etc., portanto, a API limpa é recomendada após o Java 9. As referências do finalizador são usadas para gerenciar esses finalizadores .

  1. algoritmo de coleta de lixo
  • Algoritmo Mark-clear: primeiro marque todos os objetos sobreviventes, depois exclua todos os objetos não marcados e suas referências e, finalmente, recupere o espaço de memória ocupado pelos objetos excluídos.

    Desvantagens: a fragmentação da memória não pode ser evitada; o processo de marcação e limpeza pode afetar o desempenho do aplicativo.

  • Algoritmo de classificação de marca: primeiro marca todos os objetos sobreviventes, depois os compacta em uma extremidade da memória, limpa outros objetos não marcados e suas referências e, finalmente, recupera o espaço de memória ocupado pelos objetos excluídos.

    Vantagens: pode evitar a fragmentação da memória

    Desvantagens: A localização dos objetos sobreviventes precisa ser movida, o que afeta o desempenho do aplicativo.

  • Algoritmo de cópia: copie os objetos sobreviventes existentes para outra área de memória e, em seguida, limpe todos os objetos não copiados na área de memória antiga e, finalmente, obtenha um espaço de memória contínuo.

    Vantagens: pode evitar a fragmentação da memória

    Desvantagens: Espaço de memória adicional é necessário para armazenar objetos copiados, o que também aumentará a sobrecarga de tempo do GC.

  • Algoritmo de recuperação geracional: com base na suposição geracional (ou seja, o ciclo de vida de um objeto é dividido em diferentes estágios e objetos em diferentes estágios têm diferentes probabilidades de sobrevivência), a memória é dividida em dois ou mais espaços, geralmente chamados de novos geração e a velha geração .s . Os objetos da geração mais jovem têm um ciclo de vida curto, então o algoritmo de cópia é usado; os objetos da geração antiga têm um ciclo de vida longo, então o algoritmo de compressão de marca é usado.

    Nova geração: A nova geração geralmente consiste em três partes, uma parte é o Eden Space e as outras duas partes são o Survivor Space.

    Geração antiga: A geração antiga é usada para armazenar objetos com um longo ciclo de vida , e esses objetos vêm da nova geração. Como o ciclo de vida dos objetos na geração antiga é relativamente longo, o algoritmo mark-clear ou mark-compact é usado para coleta de lixo. Ao realizar a coleta de lixo, a maior parte do espaço da geração antiga não precisa ser digitalizada, apenas uma parte dos objetos ativos e possíveis referências à geração jovem existentes nele serão verificadas.

    • No início, o Eden Space está vazio e, à medida que novos objetos são criados, os objetos são armazenados no Eden Space.

    • Quando o Eden Space for preenchido pela primeira vez, um Minor GC será acionado. No Minor GC, todos os objetos sobreviventes no Eden Space serão verificados e transferidos para uma área livre na área sobrevivente por meio do algoritmo de cópia .

    • O Eden Space subsequente tem memória insuficiente, e os objetos sobreviventes no Eden Space e da área de sobreviventes são transferidos para a área de sobreviventes por meio do algoritmo de cópia .

    • Quando os objetos da nova geração ainda estiverem em estoque após vários GCs, eles entrarão na geração antiga.

    • Se durante o GC menor, a memória da geração mais jovem não for suficiente para manter os objetos sobreviventes e as duas áreas sobreviventes não puderem conter todos os objetos sobreviventes, esses objetos serão promovidos para a geração anterior.

    • Quando não houver espaço suficiente na geração antiga, ele tentará acionar o Minor GC primeiro; quando não puder mais liberar espaço de memória suficiente através do Minor GC, ele acionará o Full GC.

  1. tipo de coleta de lixo
  • Full GC: principalmente recicla objetos inúteis na geração antiga. O ciclo de vida dos objetos na geração antiga é relativamente longo, portanto a frequência do Full GC é relativamente baixa, mas o Full GC suspenderá todos os threads do aplicativo (Stop The World, STW) e levará mais tempo para ser concluído, portanto, afetam o desempenho do sistema têm um certo impacto. Durante o processo Full GC, a máquina recupera todo o heap , incluindo a nova geração e a geração antiga, para recuperar mais espaço de memória.

    Como o GC completo é acionado:

    • Quando a nova geração e a geração antiga estiverem cheias de memória, o Full GC será acionado para uma coleta de lixo abrangente.

    • Quando o CMS GC não puder lidar com a fragmentação da memória e atingir a condição de acionamento do GC especificada, ele acionará a limpeza do GC completo.

    • Quando o espaço na área Perm não for suficiente para acomodar novos objetos, a JVM acionará o Full GC para recuperar o lixo na área Perm para liberar memória.

    • Quando o método System.gc() é chamado, ele forçará o Full GC para uma coleta de lixo abrangente.

  • Minor GC: recicla principalmente objetos inúteis na nova geração. Como o ciclo de vida dos objetos da nova geração é curto, a frequência do Minor GC é relativamente alta e geralmente não afetará o desempenho do sistema. Durante o processo de Minor GC, a máquina virtual suspende temporariamente todos os threads do aplicativo (Stop The World, STW) para recuperar o espaço de memória.

  • GC Misto: É um método de coleta de lixo entre GC Menor e GC Completo. No coletor de lixo G1 após o JDK 8, o Mixed GC foi introduzido.

  • System GC: A coleta de lixo do sistema é um método de coleta de lixo acionado automaticamente pelo sistema. A GC do sistema geralmente é executada pelo programa aplicativo chamando o método System.gc() para solicitar que o sistema execute operações de coleta de lixo. Chamar o método System.gc() para solicitar a execução do System GC geralmente aciona um Full GC, ou seja, coleta de lixo de toda a memória heap.

  1. coletor de lixo
  • Categorias comuns:

    • serial

      • O coletor de lixo mais simples

      • Usar thread único para coleta de lixo: o STW será acionado quando a coleta de lixo for executada até que a coleta seja concluída

      • adequado para pequenas aplicações

      • simples e leve

      • Combinação: Serial + Serial Antigo

    • Prioridade de taxa de transferência

      • Projetado para maximizar o rendimento da coleta de lixo

      • Coleta de lixo usando multithreading

      • Adequado para aplicativos que se concentram na taxa de transferência do sistema, como processamento de dados de back-end, processamento em lote, etc.

      • Aplicável a cenários com grande memória heap

      • Deixe o tempo da unidade, o tempo STW ser o mais curto

      • Combinação: Parallel Scavenge + Parallel Old

    • Prioridade de tempo de resposta

      • Projetado para minimizar as pausas na coleta de lixo

      • Coleta de lixo usando multithreading

      • Adequado para aplicativos com requisitos rígidos de tempo de resposta, como aplicativos da Web e sistemas em tempo real

      • Aplicável a cenários com grande memória heap

      • Torne o tempo STW único o mais curto

  • Coletores de lixo JVM comuns:

    • Coletor serial: Este é um coletor de lixo básico da JVM, que usa um único thread para coleta de lixo. O coletor Serial é adequado para pequenas aplicações, e sua simplicidade e leveza o tornam muito popular em aplicações cliente.

    • Coletor paralelo (paralelo): O coletor paralelo é semelhante ao coletor serial, mas usa vários encadeamentos para coleta de lixo. O coletor paralelo é adequado para aplicativos grandes e sua capacidade de simultaneidade pode melhorar a velocidade de resposta do aplicativo.

    • Coletor CMS (concorrente): O coletor CMS (Concurrent Mark Sweep) é um coletor de lixo com tempo de pausa baixo que usa simultaneidade multiencadeada para coleta de lixo. É adequado para cenários com requisitos rígidos de tempo de resposta do aplicativo, como aplicativos da Web. O CMS usa um algoritmo de varredura de marca, que é dividido nas 4 etapas a seguir:

      • Marcação inicial: Marque os objetos com os quais o GC Roots pode se relacionar diretamente e será STW.

      • Marcação simultânea: GC Roots Tracing, que pode ser executado simultaneamente com as threads do usuário.

      • Remarcação: rejulgamento da sobrevivência de objetos gerados durante o período de marcação e correção da marcação desses objetos. O tempo de execução é relativamente curto em comparação com a marcação simultânea e será STW.

      • Limpeza simultânea: a limpeza de objetos pode ser executada simultaneamente com threads de usuário.

    • Coletor G1: O coletor de lixo G1 é um coletor de lixo baseado em região . Ele adota a ideia de região (Region) e divide a memória heap Java em várias regiões (Region) de tamanho igual. O tamanho de cada região é geralmente 1 MB ou maior. O coletor de lixo G1 determina quais áreas devem ser recuperadas primeiro calculando o rendimento de recuperação de cada área.

      Rendimento de recuperação é a proporção da quantidade de memória que pode ser liberada pela recuperação de uma região para a quantidade de memória atualmente usada pela região. O coletor de lixo G1 calcula o rendimento de recuperação para cada região por meio das seguintes etapas:

      1. Rastreie a alocação e coleta de objetos para cada região para calcular a porcentagem de lixo em cada região .

      2. Marque objetos ativos em cada região durante a coleta de lixo Calcule a porcentagem de objetos ativos em cada região .

      3. Calcule o rendimento da reciclagem para cada região multiplicando a proporção de lixo e a proporção de objetos sobreviventes em cada região.

      Após calcular o rendimento de recuperação de cada área, o coletor de lixo G1 determinará quais áreas devem ser recuperadas primeiro de acordo com o tamanho do rendimento de recuperação, ou seja, priorizar a reciclagem das áreas com alto rendimento de recuperação para maximizar a liberação de memória disponível .

  • coletor de lixo padrão

    • Java 8 e anterior: coletor de lixo serial

    • Java 9 e posterior: G1 Garbage Collector

  • A diferença entre CMS e G1:

característica CMS G1
Algoritmo de Reciclagem marcar-claro Algoritmo de Coleta de Lixo Composto
problema de fragmentação gerar muitos detritos Divida o heap Java em várias áreas de tamanho igual para reduzir a fragmentação
tempo de pausa A execução do aplicativo precisa ser interrompida, o tempo de pausa é longo Use encadeamentos simultâneos para coleta de lixo e permita que as tarefas de coleta de lixo sejam distribuídas, com tempos de pausa curtos
espaço extra Precisa de espaço extra para guardar objetos de lixo Parte do heap Java pode ser usado para coleta de lixo sem espaço adicional
Cena aplicável Aplicativos sensíveis a tempos de pausa Aplicativos que exigem grandes heaps e baixa latência para minimizar os tempos de pausa e reduzir a fragmentação da memória durante a coleta de lixo

Acho que você gosta

Origin blog.csdn.net/m0_56170277/article/details/130468533
Recomendado
Clasificación