Perspectiva de compilação detalhada da JVM para entender o ciclo de vida de variáveis locais

Introdução

Qual é o ciclo de vida das variáveis ​​definidas nos métodos java? É necessário esperar até o final do método para que o objeto criado seja reciclado?

Com esta pergunta, vamos dar uma olhada no artigo de hoje.

O ciclo de vida das variáveis ​​locais

Em uma classe, os tipos de variáveis ​​incluem variáveis ​​de classe, variáveis ​​de membro e variáveis ​​locais.

Variáveis ​​locais referem-se às variáveis ​​definidas no método.Se definirmos uma variável no método, qual é o ciclo de vida desta variável?

por exemplo:

public void test(){
  Object object = new Object();
  doSomeThingElse(){
    ...
  }
}

No método de teste acima, uma variável local do objeto é definida e, em seguida, outro método é executado.

Porque em Java, não podemos controlar diretamente o ciclo de vida de um objeto, e a coleta de objetos é realizada automaticamente pelo coletor de lixo.

De modo geral, este objeto permanecerá até o final de toda a execução do teste antes de ser reciclado.

Agora, consideramos um caso especial: se o método doSomeThingElse for um loop while e nunca terminar, o objeto criado será reciclado? Ou está sempre na memória?

Deixe-me falar sobre nossa conclusão primeiro, a JVM é muito inteligente e pode detectar essa situação e reciclar o objeto.

por exemplo

Para explicar melhor o problema, personalizamos um objeto Teste e imprimimos as informações correspondentes antes de ser criado e reciclado.

public static class Test {
    public Test() {
      System.out.println("创建对象 " + this);
    }

    public void test() {
      System.out.println("测试对象 " + this);
    }

    @Override
    protected void finalize() throws Throwable {
      System.out.println("回收对象 " + this);
    }
  }

Em seguida, faça dois testes. O primeiro teste não tem um loop infinito e o segundo teste mantém um loop infinito. O loop é controlado por um sinalizador de variável volátil:

public static void main(String[] args) throws InterruptedException {
    System.out.println("开始测试1");
    resetFlag();
    flag = true;
    testLocalVariable();

    System.out.println("等待Test1结束");
    Thread.sleep(10000);

    System.out.println("开始测试2");
    flag = true;
    testLocalVariable();
  }

Dê uma olhada na definição do método testLocalVariable:

public static void testLocalVariable() {
    Test test1 = new Test();
    Test test2 = new Test();
    while (flag) {
      // 啥都不做
    }
    test1.test();
  }

Em seguida, começamos outro thread para fazer o tempo GC. Agora que tudo está pronto, vamos executar:

 开始测试1
 创建对象 [com.flydean.LocalVariableReachability$Test@119d7047](mailto:com.flydean.LocalVariableReachability$Test@119d7047)
 创建对象 [com.flydean.LocalVariableReachability$Test@776ec8df](mailto:com.flydean.LocalVariableReachability$Test@776ec8df)
 回收对象 [com.flydean.LocalVariableReachability$Test@776ec8df](mailto:com.flydean.LocalVariableReachability$Test@776ec8df)
 测试对象 [com.flydean.LocalVariableReachability$Test@119d7047](mailto:com.flydean.LocalVariableReachability$Test@119d7047)
等待Test1结束
回收对象 [com.flydean.LocalVariableReachability$Test@119d7047](mailto:com.flydean.LocalVariableReachability$Test@119d7047)

开始测试2
创建对象 [com.flydean.LocalVariableReachability$Test@4eec7777](mailto:com.flydean.LocalVariableReachability$Test@4eec7777)
创建对象 [com.flydean.LocalVariableReachability$Test@3b07d329](mailto:com.flydean.LocalVariableReachability$Test@3b07d329)
 回收对象 [com.flydean.LocalVariableReachability$Test@3b07d329](mailto:com.flydean.LocalVariableReachability$Test@3b07d329)

Olhando para o resultado do teste 1 primeiro, podemos ver que o segundo objeto foi reciclado antes de chamar test1.test ().

Olhando o resultado do teste 2, podemos ver que o segundo objeto também foi reciclado.

Os resultados mostram que a JVM é inteligente o suficiente para otimizar o ciclo de vida das variáveis ​​locais.

Razões para otimização

Vamos considerar, em que estágio a JVM otimiza o ciclo de vida das variáveis ​​locais?

Obviamente, essa otimização não é feita durante a compilação, mas durante o tempo de execução.

Usamos -XX: + PrintAssembly para analisar o código de montagem:

Em primeiro lugar, aprendi minha linguagem assembly há muitos anos. Se houver erros na explicação, corrija-me.

Deixe-me falar sobre os dois conceitos rbx e r10 são ambos registradores de CPU de 64 bits e r10d são os 32 bits inferiores de r10.

Primeiro olhe para a caixa vermelha 1. A caixa vermelha 1 significa que o que está armazenado em rbx é um objeto Teste na classe LocalVariableReachability que definimos.

Observe a caixa vermelha 2. A caixa vermelha 2 significa que r10 agora salva uma instância da classe LocalVariableReachability.

A caixa vermelha 3 representa os objetos armazenados no ImmutableOopMap ao entrar no loop while.Você pode ver que nele há apenas r10 e rbx, ou seja, apenas a instância da classe e uma das instâncias Test.

O que é Red Box 4? A caixa vermelha 4 representa um ponto seguro, que é um ponto seguro durante a coleta de lixo. Neste ponto seguro, se houver objetos que não são mais usados, eles serão reciclados.

Como há apenas dois objetos em ImutableOopMap, a instância de teste restante será reciclada.

Algumas perguntas da entrevista de alta frequência coletadas no último 2020 (todas organizadas em documentos), há muitos produtos secos, incluindo mysql, netty, spring, thread, spring cloud, jvm, código-fonte, algoritmo e outras explicações detalhadas, bem como planos detalhados de aprendizagem, entrevistas, classificação de perguntas, etc. Para aqueles que precisam obter esses conteúdos, adicione Q como: 11604713672

Acho que você gosta

Origin blog.csdn.net/weixin_51495453/article/details/113665804
Recomendado
Clasificación