[Noções básicas de JVM] Noções básicas de JVM

A localização da JVM

O aplicativo (aplicativo Java) é executado no JRE (o JRE contém a JVM), o JRE é executado no sistema operacional (Windows, Mac) e o sistema operacional é executado na arquitetura de hardware (Intel, Spac...).

Três JVMs

  • Sol: HotSpot é o mais utilizado (usamos)
  • BEA: JRockit
  • IBM:J9VM

Arquitetura JVM

Ajuste de JVM: 99% estão na área de método e heap, na maioria das vezes o heap é ajustado. JNI (Java Native Interface): interface de método nativo
insira a descrição da imagem aqui
insira a descrição da imagem aqui

carregador de classes

Função: carregar o arquivo de classe
Por exemplo: new Student();(a instância específica está no heap e o nome da variável de referência é colocado na pilha)

  • O carregador que vem com a máquina virtual
  • Inicie o carregador de classe (raiz)
  • carregador de classe de extensão
  • carregador de aplicativos

insira a descrição da imagem aqui
insira a descrição da imagem aqui

Mecanismo de Delegação Parental

conceito

Quando um carregador de classes precisa carregar um determinado arquivo .class, ele primeiro confia essa tarefa ao seu carregador de classes superior e executa esta operação recursivamente.Se o carregador de classes superior não o carregar, ele carregará a própria classe.

exemplo

Hello.classQuando tal arquivo deve ser carregado.
Independentemente do nosso carregador de classes personalizado, primeiro verificaremos se ele foi carregado em AppClassLoader e, em caso afirmativo, não há necessidade de carregá-lo novamente. Caso contrário, o carregador pai será obtido e o método loadClass do carregador pai será chamado .
Da mesma forma, a classe pai irá primeiro verificar se foi carregada e, caso contrário, subirá. Observe que esse processo recursivo, até chegar ao classLoader do Bootstrap , está verificando se foi carregado, e não escolherá carregá-lo sozinho.
Até BootstrapClassLoader , não há carregador pai. Nesse momento, começo a pensar se posso carregá-lo. Se não conseguir carregá-lo, vou afundar no carregador filho para carregá-lo, até chegar ao fundo. Se não há nenhum carregador que possa carregá-lo, ele irá lançar ClassNotFoundException.

insira a descrição da imagem aqui

efeito

  • 1. Evite o carregamento repetido do mesmo .class. Solicite o acima por meio de atribuição, após o carregamento não há necessidade de carregá-lo novamente. Garanta a segurança dos dados.
  • 2. Certifique-se de que core.class não possa ser adulterado. Através da delegação, o .class principal não será adulterado, mesmo que seja adulterado, não será carregado e, mesmo que seja carregado, não será o mesmo objeto .class. Carregadores diferentes carregam o mesmo .class e não são o mesmo objeto Class. Isso garante a segurança da execução da aula.

Por exemplo: Se alguém quiser substituir a classe de nível de sistema: String.java.
Adulterando sua implementação, sob esse mecanismo, as classes desses sistemas foram carregadas pelo Bootstrap classLoader (por quê? Porque quando uma classe precisa ser carregada, a primeira coisa a tentar carregar é o BootstrapClassLoader), então outros carregadores de classes não são O A oportunidade de carregar novamente evita até certo ponto a implantação de códigos perigosos.

Mecanismo de segurança sandbox

insira a descrição da imagem aqui
insira a descrição da imagem aqui
insira a descrição da imagem aqui
insira a descrição da imagem aqui

Componentes básicos que compõem uma sandbox

  • O verificador de bytecode (verificador de bytecode)
    garante que o arquivo de classe Java .Class siga a especificação da linguagem Java. Isso ajuda os programas Java a obter proteção de memória. Mas nem todos os arquivos de classe passarão pela verificação de bytecode, como as classes principais.
  • Carregador de classes (carregador de classes)
    onde o carregador de classes funciona no sandbox Java de três maneiras:
    • Impede que códigos maliciosos interfiram no código de boa-fé; //Modo de delegação pai
    • Protege os limites das bibliotecas confiáveis;
    • Ele coloca o código em domínios de proteção, que determinam o que o código pode fazer.

A máquina virtual fornece diferentes namespaces para classes carregadas por diferentes carregadores de classes. O namespace consiste em uma série de nomes exclusivos. Cada classe carregada terá um nome. Esse namespace é criado pela Java Virtual Machine para cada classe mantida pelo carregador de classes. nem sequer são visíveis um para o outro.

O mecanismo utilizado pelo carregador de classes é o modelo de delegação parental .

1. Comece a carregar a partir do carregador de classes da JVM mais interna, e a classe maliciosa externa com o mesmo nome não pode ser carregada e não pode ser usada;

2. Como o domínio de acesso é estritamente diferenciado pelo pacote, a classe maliciosa na camada externa não pode obter permissão para acessar a classe interna por meio do código integrado, e o código danificado naturalmente não terá efeito.

  • Controlador de acesso (controlador de acesso): O controlador de acesso pode controlar a autoridade de acesso da API principal ao sistema operacional, e a configuração de política desse controle pode ser especificada pelo usuário.
  • Gerenciador de segurança (gerenciador de segurança): é a interface principal entre a API principal e o sistema operacional. Para implementar o controle de permissão, ele tem prioridade mais alta que o controlador de acesso.
  • Pacote de segurança: as classes em java.security e as classes no pacote de extensão, permitindo aos usuários adicionar novos recursos de segurança às suas aplicações, incluindo:
    • provedor de segurança
    • resumo da mensagem
    • Keytools de assinatura digital https (é necessário certificado)
    • criptografia
    • identificar

Nativo

Aqueles com a palavra-chave nativa indicam que o escopo do Java não pode ser alcançado e você deve chamar a biblioteca subjacente da linguagem C.
Qualquer método com a palavra-chave nativa entrará na pilha de métodos locais e os outros são a pilha Java

JNI: Java Native Interface (interface de método local)

A função de chamar a interface de método local (JNI):

Expandir o uso de Java e integrar diferentes linguagens de programação para Java. A
intenção original de Java era integrar programas C/C++. C e C++ são galopantes. Se você quiser ganhar uma posição, você deve ter programas que chamam C e C++. É especialmente desenvolvido na área de memória da cidade. Marcação de blocos da cidade do distrito: Pilha de métodos nativos

Pilha de métodos nativos

Registre o método nativo, quando o mecanismo de execução (Execution Engine) for executado. Carregar métodos em **Bibliotecas Nativas** via JNI (Native Method Interface).

Raro em aplicativos de nível empresarial, aplicativos relacionados a hardware: impressoras orientadas por programas Java, equipamentos de produção de gerenciamento de sistema, etc.

Registro de PC (registro de contador de programa)

Contador de Programa: Registro do Contador de Programa

Cada thread possui um contador de programa, que é privado da thread , e é um ponteiro para o bytecode do método na área do método (usado para armazenar o endereço que aponta para a próxima instrução, que também é o código da instrução a ser executada), em o mecanismo de execução Ler a próxima instrução ocupa um espaço de memória muito pequeno, quase insignificante.

Área de Método

A área do método é compartilhada por todos os threads . Todos os campos e bytecodes do método, bem como alguns métodos especiais, como construtores, códigos de interface também são definidos aqui. Simplificando: todas as informações do método definido são armazenadas nesta área, que pertence ao compartilhamento espaço;

Variáveis ​​estáticas, constantes, informações de classe (método de construção, definição de interface), pool de constantes de tempo de execução (como: estático, final, classe (modelo de classe), pool de constantes) são armazenados na área de método, mas variáveis ​​​​de instância são armazenadas no heap memória ... Não tem nada a ver com a área do método.

Pilha (pilha Java)

Por que main() é executado primeiro e termina no final: (porque main() é colocado na pilha primeiro)

Pilha: memória da pilha, execução do programa supervisor, ciclo de vida e sincronização de threads.
Quando o thread termina, a memória da pilha é liberada.Para a pilha, não há problema de coleta de lixo.

Armazenamento de pilha: 8 tipos básicos + referência de objeto + método de instância.
Princípio de operação da pilha: o quadro de pilha (tabela de variáveis ​​locais + pilha de operandos) possui um quadro de pilha para cada método chamado.
A pilha está cheia e main() não pode terminar, um erro será gerado: stack overflowStackOverflowError

insira a descrição da imagem aqui

Pilha + heap + área de método: relacionamento interativo

insira a descrição da imagem aqui

Pilha

Uma JVM possui apenas uma memória heap e o tamanho do heap pode ser ajustado.
Depois que o carregador de classes lê o arquivo de classe, ele geralmente coloca classes, métodos, constantes, variáveis ​​e objetos reais que salvam todos os tipos de referência no heap.

A memória heap é subdividida em 3 áreas:

  • Novo Distrito (Eden District) Jovem / novo
  • área de aposentadoria antiga
  • Área permanente Perm, após JDK8, a área de armazenamento permanente mudou de nome (metaespaço)

Coleta de lixo da GC, principalmente no Eden Park e áreas de repouso.
insira a descrição da imagem aqui
Supondo que a memória esteja cheia, um erro OOM é relatado: memória heap insuficienteOutOfMemoryError:Java heap space

//-Xms8m -Xmx8m -XX:+PrintGCDetails
public static void main(String[] args) {
    
    
    String str = "javajavajavajava";

    while (true){
    
    
        str += str + new Random().nextInt(888888888)+ new Random().nextInt(21_0000_0000);
    }
}
//OutOfMemoryError:Java heap space 堆内存满了

insira a descrição da imagem aqui

Área Newborn (Jardim do Éden + Área Sobrevivente*2)

  • Um lugar onde as aulas nascem e crescem e até morrem
  • Jardim do Éden, todos os objetos foram criados recentemente no Jardim do Éden
  • Área de sobrevivente (de, para), o GC leve limpa regularmente o Jardim do Éden, e aqueles que sobrevivem são colocados na área de sobrevivente.Depois que a área de sobrevivente estiver cheia, o GC pesado limpa a área do Éden + sobrevivente , e o os sobreviventes são colocados na área de aposentadoria. Se estiverem cheios, informe o OOM.

Nota: Após pesquisa, 99% dos objetos são objetos temporários! limpo diretamente

Área idosa

O resto da nova área, GC leve não pode matar

área permanente

Esta área é residente na memória e é utilizada para armazenar os objetos de Classe e metadados de Interface transportados pelo próprio JDK. Ela armazena algumas informações de ambiente ou classe do Java runtime. Não há GC de coleta de lixo nesta área . Desligar a máquina virtual libera essa memória.

  • Antes do jdk1.6: a geração permanente, o pool constante está na área do método .
  • jdk1.7: geração permanente, mas degenera lentamente (para a geração permanente) o pool constante está no heap .
  • Após jdk1.8: Não há geração permanente e o pool constante está no metaspace .

O pool de constantes sempre esteve na área de métodos e o pool de strings nele foi salvo no heap após o JDK1.7.

Exemplo de OOM de área permanente: uma classe de inicialização que carrega um grande número de pacotes jar de terceiros. O Tomcat implanta muitos aplicativos e um grande número de classes de reflexão geradas dinamicamente. Constantemente sendo carregado. Até que a memória esteja cheia, OOM aparecerá.

A área de métodos também é chamada de non-heap (non-heap), que ainda é um heap em essência, apenas para distinguir conceitos.

O metaespaço existe logicamente, mas não fisicamente.

Ajuste de memória heap

public static void main(String[] args) {
    
    
    //返回虚拟机试图使用的最大内存
    long max = Runtime.getRuntime().maxMemory(); //字节 1024*1024
    //返回jvm初始化的总内存
    long total = Runtime.getRuntime().totalMemory();

    System.out.println("max="+max+"字节\t"+(max/(double)1024/1024+"MB"));
    System.out.println("total="+total+"字节\t"+(total/(double)1024/1024+"MB"));
    /* 运行后:
    max=1866465280字节   1780.0MB
    total=126877696字节  121.0MB
     */
    //默认情况下,分配的总内存占电脑内存1/4 初始化1/64
}

Como denunciar OOM?

  • 1. Tente expandir a memória heap. Se o erro ainda for relatado, significa que há um código de loop infinito ou código de lixo.
    Editar configuração> adicionar opção VM> Entrada: -Xms1024m -Xmx1024m -XX:+PrintGCDetails
    insira a descrição da imagem aqui
    área recém-nascido + área de velhice: 305664K + 699392K = 1005056K = 981,5M, indicando que a física do metaespaço não existe.

  • 2. Analise a memória e veja onde há um problema (ferramentas profissionais)
    para ver quais linhas do código estão erradas: ferramenta de análise de instantâneo de memória, MAT, Jprofiler
    MAT, função Jprofiler:

    • Analise arquivos de memória Dump para localizar rapidamente vazamentos de memória;
    • obter os dados na pilha
    • obter objeto grande
//-Xms 设置初始化内存分配大小 默认1/64
//-Xmx 设置最大分配内存,默认1/4
//-XX:+PrintGCDetails 打印GC垃圾回收信息
//-XX:+HeapDumpOnOutOfMemoryError //oom DUMP
//-Xms1m -Xmx8m -XX:+HeapDumpOnOutOfMemoryError
public class Demo03 {
    
    
    byte[] array = new byte[1*1024*1024]; //1m

    public static void main(String[] args) {
    
    
        ArrayList<Demo03> list = new ArrayList<>();
        int count = 0;
        try {
    
    
            while (true){
    
    
                list.add(new Demo03()); //不停地把创建对象放进列表
                count = count + 1;
            }
        } catch (Exception e) {
    
    
            System.out.println("count: "+count);
            e.printStackTrace();
        }
    }
}

insira a descrição da imagem aqui
insira a descrição da imagem aqui

GC (coleta de lixo)

insira a descrição da imagem aqui
Quando a JVM executa a GC, ela não recicla uniformemente as três áreas da nova geração, a área sobrevivente e a área antiga. Na maioria das vezes, a nova geração é reciclada

Dois tipos de GC: GC leve, GC pesado (GC completo, GC global)

contagem de referência

Geralmente a JVM não é usada, há muitos objetos de projeto grandes
insira a descrição da imagem aqui

algoritmo de cópia

-XX:MaxTenuringThreshold=15Defina o número de condições de sobrevivência para entrar na velhice.
insira a descrição da imagem aqui
insira a descrição da imagem aqui
Vantagens: sem fragmentação de memória, alta eficiência de memória
Desvantagens: espaço de memória é desperdiçado (uma área sobrevivente está sempre vazia); supondo que o objeto esteja 100% ativo, o custo de cópia é alto.
O melhor cenário de uso para o algoritmo de replicação: quando a sobrevivência do objeto é baixa, a nova área.

marcar claro

insira a descrição da imagem aqui
Vantagens: Não é necessário espaço adicional e o algoritmo de cópia é otimizado.
Desvantagens: Duas varreduras, uma grande perda de tempo, gerarão fragmentação de memória.

Compressão de tags (limpeza de marcas): reotimização

Trilogia: Marcar – Limpar – Comprimir
insira a descrição da imagem aqui

Compressão de varredura de marca: reotimização

Comprima sempre que a marca for apagada ou se a fragmentação da memória se acumular até certo ponto.

Algoritmo de Coleta Geracional

De acordo com o ciclo de vida do objeto de memória, a memória é dividida em várias partes, e a JVM geralmente divide a memória em nova geração e antiga geração.
Na nova geração, um grande número de objetos morre e um pequeno número de objetos sobrevive, então o algoritmo de cópia pode ser usado para completar a coleção apenas pagando o custo de copiar um pequeno número de objetos sobreviventes; na geração antiga, porque a taxa de sobrevivência dos objetos é extremamente alta, não há espaço adicional para
eles. A garantia de alocação é realizada, portanto, a limpeza de marcas ou algoritmo de classificação de marcas é usado para reciclagem;
insira a descrição da imagem aqui

Resumir

Eficiência de memória: Algoritmo de replicação > Algoritmo de varredura de marca > Algoritmo de compactação de marca (complexidade de tempo)

Uniformidade de memória: algoritmo de cópia = algoritmo de compactação de marca> algoritmo de remoção de marca

Utilização de memória: Algoritmo de compactação de marca = Algoritmo de limpeza de marca> Algoritmo de cópia

Não existe um algoritmo melhor, apenas um algoritmo adequado (GC também é conhecido como algoritmo de coleta geracional).

  • Geração Jovem: A taxa de sobrevivência é baixa e o algoritmo de replicação é usado.
  • Geração antiga: alta taxa de sobrevivência, grande área, compressão clara.

Acho que você gosta

Origin blog.csdn.net/qq_44033208/article/details/132470273
Recomendado
Clasificación