Série Drunk: mecanismo de coleta de lixo JVM e estratégia de alocação de memória de Drunk

Clique na fonte azul acima e selecione "Conta oficial da estrela"

Artigos de alta qualidade, entregues imediatamente

99 conjuntos de projetos de combate reais de nível empresarial Java

4000G Architect Information

Chumbo: A conta oficial vai lançar uma série de artigos técnicos depois de beber, todos os quais são produtos secos, espero não ficar bêbado!

Antes de beber, devemos fazer um comentário inicial. Acho que todos já leram o artigo anterior. Foi a primeira vez que bebemos. Quem quiser revisar, pode continuar a revisá-lo!

A seguir, vamos tomar um bom gole de novo, então os pratos para acompanhar o álcool devem ser indispensáveis, e serão servidos dois acompanhamentos primeiro.

1. Método de contagem de referência ????

Adicione um contador de referência ao objeto. Sempre que houver uma referência a ele, o valor do contador será +1; quando a referência for inválida, o valor do contador será -1; a qualquer momento um objeto com um contador 0 não pode mais ser usado.

2. Análise e cálculo de acessibilidade ????

Usando uma série de objetos que se tornam "GC Roots" como ponto de partida, partindo desses nós e procurando para baixo, o caminho pesquisado é chamado de cadeia de referência. Quando não há cadeia de referência de um objeto para GC Roots, fica comprovado que o objeto não está disponível.

Alguns bebedores podem não entender, o que é GC Roots, vou te contar se eu beber um ????

1. O objeto referenciado na pilha da máquina virtual (tabela de variável local no frame da pilha) [objeto de new () no método]

2. O objeto referenciado pela propriedade estática da classe na área do método [static A a = new A ()]

3. Objetos referenciados por constantes na área do método

4. Objetos referenciados por JNI (em geral, métodos nativos) na pilha de métodos nativos

Venha para uma foto para que os bebedores entendam melhor

Precisa de uma torrada depois de comer ????

3. Usando o algoritmo de análise de alcançabilidade, o objeto sobreviveu ou foi destruído ????

Java usa o algoritmo de análise de acessibilidade para determinar se o objeto está vivo.

Objetos que não são alcançáveis ​​no algoritmo de análise de alcançabilidade não são "devem ser destruídos". No momento, eles estão em estágio de "provação". Para realmente anunciar a morte de um objeto, eles devem passar por pelo menos dois processos de marcação: se o objeto não tiver uma cadeia de referência conectada ao GC Roots após a análise de acessibilidade , será a primeira vez. Marque e execute um filtro, a condição do filtro é se é necessário que este objeto execute o método finalize (). Quando o objeto não cobre o método finalize (), ou o método finalize () foi chamado pela máquina virtual, a máquina virtual considera ambos os casos como "não há necessidade de executar". Se for necessário que este objeto execute o método finalize (), então este objeto salva a si mesmo com sucesso ao executar este método - contanto que ele restabeleça um relacionamento com qualquer objeto na cadeia de referência, como atribuir-se a uma classe variável ou A variável membro do objeto, não será reciclada quando for marcada pela segunda vez.

Algoritmo de coleta de lixo

Um, algoritmo de varredura de marca ??

O algoritmo de coleta mais básico, como seu nome, é dividido em duas etapas: "marcação" e "limpeza": primeiro, todos os objetos que precisam ser reciclados são marcados e todos os objetos marcados são reciclados uniformemente após a conclusão da marcação. Suas principais deficiências têm pontos positivos: um é o problema de eficiência, a eficiência dos dois processos de marcação e clareamento não é alta; o outro é o problema de espaço, depois que a marca é apagada, um grande número de fragmentos de memória descontínua será gerado , e muita fragmentação de espaço pode causar mais tarde. Quando um objeto grande precisa ser alocado durante a execução do programa, ele não consegue encontrar memória contígua suficiente e precisa acionar outra coleta de lixo com antecedência.

Em segundo lugar, o algoritmo de replicação ???

Para resolver o problema de eficiência, surgiu um algoritmo de coleta denominado "cópia", que divide a memória disponível em duas partes iguais, e utiliza apenas uma peça por vez. Quando este bloco for usado, copie os objetos sobreviventes para outro bloco e, em seguida, limpe o espaço de memória usado de uma vez, para que toda a metade da área seja recuperada e a memória não seja considerada durante a alocação de memória. , basta mover o ponteiro e alocar a memória em ordem, o que é simples de implementar e eficiente de executar. Só que o custo desse algoritmo é reduzir a memória pela metade, o que é muito alto.

Três, algoritmo de classificação de marcas ???

O processo de marcação ainda é o mesmo que o algoritmo "mark-sweep", mas as etapas subsequentes não são para limpar diretamente os objetos recicláveis, mas para mover todos os objetos sobreviventes para uma extremidade e, em seguida, limpar diretamente a memória fora do limite da extremidade .

Quarto, o uso do algoritmo de coleta geracional ???

A atual coleta de lixo das máquinas virtuais comerciais adota o algoritmo de "coleta geracional", que divide a memória em vários blocos de acordo com o ciclo de vida do objeto. Geralmente, o heap Java é dividido em nova geração e velha geração, e o algoritmo de coleta mais adequado é adotado de acordo com as características de cada geração. Na nova geração, um grande número de objetos morrem cada vez que uma coleta de lixo, e apenas alguns sobrevivem, então o algoritmo de replicação é selecionado e a coleta pode ser concluída pagando uma pequena quantia do custo de replicação do objetos sobreviventes. Na velhice, como o objeto tem uma alta taxa de sobrevivência e nenhum espaço extra para sua garantia de alocação, ele deve ser reciclado usando o algoritmo "marcar e limpar" ou "marcar e classificar".

Estratégia de alocação de memória

Em geral, a alocação de memória de objetos é alocada na pilha. Os objetos são alocados principalmente na área Éden da geração jovem. Em alguns casos, eles podem ser alocados diretamente na geração anterior. As regras de alocação não são 100 % fixo. Os detalhes dependem de qual combinação de coletores de lixo é usada atualmente, bem como das configurações de parâmetros relacionados à memória na máquina virtual.

1. Os objetos estão alocados na área do Éden da nova geração ????

Na maioria dos casos, os objetos são alocados na área do Éden da geração jovem. Quando a área do Éden não tem espaço suficiente para alocação, a máquina virtual iniciará um GC secundário. Use o código para demonstrar aos bebedores

/**
 * 对象优先在Eden 区分配
 *
 * 虚拟机参数设置:-verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails
 *  -verbose:gc 在控制台输出GC情况
 *  -Xms20M -Xmx20M -Xmn10M 限制Java堆大小为20MB,不可扩展,其中10MB分配给新生代,剩下10MB分给老年代
 *  -XX:+PrintGCDetails 收集器日志参数,告诉虚拟机在发生垃圾收集行为时打印内存回收日志,并且在进程退出的时候输出当前的内存各区域分配情况
 * Created by lxs.
 * 2020/5/22 6:25 PM
 */
public class TestMinorGC {


    private static final int _1MB = 1024 * 1024;


    public static void main(String[] args) {
        byte[] obj1, obj2, obj3;


        obj1 = new byte[2 * _1MB];
        obj2 = new byte[2 * _1MB];
        obj3 = new byte[3 * _1MB];  // 发生Minor GC
    }


}

Execute conforme mostrado na figura abaixo:

A primeira caixa vermelha significa que o resultado deste GC é que o Cenozóico 5650 KB torna-se 448 KB

O total de 5650 KB na segunda caixa vermelha torna-se 4544 KB, o que não diminui muito. Isso ocorre porque os dois objetos obj1 e obj2 estão vivos e a máquina virtual dificilmente encontra objetos que possam ser reciclados.

A terceira caixa vermelha representa a área do Éden, o sobrevivente da área e o sobrevivente para a área. A proporção do tamanho da memória é de 8: 1: 1 e o total é exatamente 10 MB.

A quarta caixa vermelha tem 10 MB na idade avançada.

A razão para este GC é que ao alocar memória para obj3, a área Eden foi ocupada pelo menos 4 MB, e o espaço restante é insuficiente para alocar os 3 MB de memória exigidos por obj3, então ocorreu um GC Secundário. Durante o GC, a máquina virtual descobriu que todos os dois objetos de 2 MB existentes não podiam ser colocados no espaço do Survivor, então ela teve que ser transferida para a velhice por meio do mecanismo de garantia de alocação com antecedência.

Depois que o CG termina, o objeto obj3 de 3 MB é alocado no Eden, então o resultado da execução do programa é que Eden ocupa 3 MB (obj3), Survivor fica inativo e a idade avançada ocupa 4 MB (obj1, obj2). Isso pode ser comprovado pelo log do GC.

Em segundo lugar, o grande objeto entra diretamente na velhice ????

/**
 * 大对象直接进入老年代
 *
 * 虚拟机参数设置:-verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:PretenureSizeThreshold=3145728
 *  -verbose:gc 在控制台输出GC情况
 *  -Xms20M -Xmx20M -Xmn10M 限制Java堆大小为20MB,不可扩展,其中10MB分配给新生代,剩下10MB分给老年代
 *  -XX:+PrintGCDetails 收集器日志参数,告诉虚拟机在发生垃圾收集行为时打印内存回收日志,并且在进程退出的时候输出当前的内存各区域分配情况
 *  -XX:PretenureSizeThreshold=3145728 大于这个设置值的对象直接分配在老年代中,即大于3MB
 *  -XX:PretenureSizeThreshold 这个参数只对Serial和ParNew两款收集器有效,我的是用的Parallel Scavenge收集器,所以不顶用,我直接new了大一点的对象,7MB的直接分配到老年代了
 * Created by lxs.
 * 2020/5/22 6:25 PM
 */
public class TestBigObj {


    private static final int _1MB = 1024 * 1024;


    public static void main(String[] args) {
        byte[] obj;


        obj = new byte[7 * _1MB];
    }


}

Execute conforme mostrado na figura abaixo:

No código acima, o objeto criado é alocado diretamente para a velhice.Veja a terceira caixa vermelha.O objeto obj tem 7MB e a velhice tem 10MB, ocupando 79%. Mas vamos olhar para as duas primeiras caixas vermelhas novamente. A área do Éden não aloca objetos, mas ainda ocupa parte de sua memória. Isso porque quando a própria máquina virtual é carregada, ela pode ter seus próprios objetos internos, portanto, ocupa o memória. Digamos, a esta altura, todos devem ser capazes de entender a primeira parte do código. Os três objetos somam 7 MB. A área do Éden deve ser capaz de caber. Claro que não, mais a memória ocupada pela própria máquina virtual. Irá acionar Minor GC.

Por falar no último, vamos fazer um juntos. Antes de fazer isso, quero dizer algumas palavras. Você costuma ouvir Minor GC, Major GC e Full GC. O que isso significa? Na verdade, é a nova geração de GC, que é chamado Minor GC; Old geração GC, chamado Major GC; Full GC significa que tanto a geração jovem quanto a velha são recicladas, ok, todos, vocês podem levantar um copo ????

Existem recomendações quentes ??

A estrutura de acesso a banco de dados Java mais popular (camada DAO)

E quanto àqueles que desejam substituir C e Java agora?

Por que o Redis de thread único pode atingir um QPS de nível de milhão?

Produtos secos: um texto para entender como as solicitações do cliente chegam ao servidor

Compartilhamento de produtos secos : digitalize o código QR para seguir a conta pública abaixo e responda a " 99 " em segundo plano para receber 99 conjuntos de projetos de combate reais + informações

O carregamento quer se concentrar no tesouro de carga do flash do programador do processo

Se o artigo ajudar, leia e encaminhe-o.

Obrigado pelo seu apoio (* ^ __ ^ *)

Acho que você gosta

Origin blog.csdn.net/qq_17231297/article/details/106435892
Recomendado
Clasificación