Implementar o compilador just-in-time do ART

O ambiente de execução do Android (ART) inclui um compilador just-in-time (JIT) com criação de perfil de código que melhora continuamente o desempenho dos aplicativos Android à medida que são executados. O compilador JIT complementa o compilador antecipado (AOT) atual do ART e melhora o desempenho de execução, economiza espaço de armazenamento e acelera as atualizações de aplicativos e do sistema. Ele também melhora o compilador AOT, evitando a lentidão do sistema durante atualizações automáticas de aplicativos ou recompilação de aplicativos durante atualizações over-the-air (OTA).

Embora o JIT e o AOT usem o mesmo compilador com um conjunto semelhante de otimizações, o código gerado pode não ser idêntico. O JIT usa informações de tipo de tempo de execução, faz um inlining melhor e possibilita a compilação de substituição na pilha (OSR, na sigla em inglês), o que gera um código ligeiramente diferente.

Arquitetura JIT

Arquitetura JIT
Figura 1. Arquitetura JIT.

Compilação JIT

A compilação JIT envolve as seguintes atividades:

Compilação guiada por perfil
Figura 2. Compilação guiada por perfil.
  1. O usuário executa o app, que aciona o ART para carregar o arquivo .dex.
    • Se o arquivo .oat (o binário AOT do arquivo .dex) estiver disponível, o ART o usará diretamente. Embora os arquivos .oat sejam gerados regularmente, eles nem sempre contêm código compilado (binário AOT).
    • Se o arquivo .oat não tiver código compilado, o ART vai executar o JIT e o interpretador para executar o arquivo .dex.
  2. A JIT é ativada para qualquer aplicativo que não seja compilado de acordo com o filtro de compilação speed (que diz "compile o máximo possível do app").
  3. Os dados do perfil JIT são despejados em um arquivo em um diretório do sistema que só o aplicativo pode acessar.
  4. O daemon de compilação AOT (dex2oat) analisa esse arquivo para direcionar a compilação.

    Daemon JIT
    Figura 3. Atividades do daemon JIT.

O serviço do Google Play é um exemplo usado por outros aplicativos que se comportam de maneira semelhante às bibliotecas compartilhadas.

Fluxo de trabalho JIT

Arquitetura JIT
Figura 4. Fluxo de dados JIT.
  • As informações de criação de perfil são armazenadas no cache de código e sujeitas à coleta de lixo sob pressão de memória.
    • Não há garantia de que um snapshot feito quando o aplicativo estava em segundo plano vai conter dados completos (ou seja, tudo o que foi JITed).
    • Não há tentativa de garantir que tudo seja gravado, já que isso pode afetar o desempenho do tempo de execução.
  • Os métodos podem estar em três estados diferentes:
    • interpretado (código dex)
    • Compilado JIT
    • Compilado com AOT
    Se houver código JIT e AOT (por exemplo, devido a desotimizações repetidas), o código JIT será preferido.
  • O requisito de memória para executar o JIT sem afetar o desempenho do app em primeiro plano depende do app em questão. Apps grandes exigem mais memória do que apps pequenos. Em geral, apps grandes se estabilizam em torno de 4 MB.

Ativar a geração de registros JIT

Para ativar o registro JIT, execute os seguintes comandos:

adb root
adb shell stop
adb shell setprop dalvik.vm.extra-opts -verbose:jit
adb shell start

Desativar JIT

Para desativar o JIT, execute os seguintes comandos:

adb root
adb shell stop
adb shell setprop dalvik.vm.usejit false
adb shell start

Forçar compilação

Para forçar a compilação, execute o seguinte:

adb shell cmd package compile

Casos de uso comuns para forçar a compilação de um pacote específico:

  • Com base em perfis:
    adb shell cmd package compile -m speed-profile -f my-package
    
  • Completa:
    adb shell cmd package compile -m speed -f my-package
    

Casos de uso comuns para a compilação forçada de todos os pacotes:

  • Com base em perfis:
    adb shell cmd package compile -m speed-profile -f -a
    
  • Completa:
    adb shell cmd package compile -m speed -f -a
    

Remover dados do perfil

No Android 13 ou versões anteriores

Para limpar os dados do perfil local e remover o código compilado, execute o seguinte:

adb shell pm compile --reset 

No Android 14 ou versões mais recentes

Para limpar apenas os dados do perfil local:

adb shell pm art clear-app-profiles 

Observação: ao contrário do comando para o Android 13 ou versões anteriores, esse comando não limpa os dados do perfil externo (`.dm`) que são instalados com o app.

Para limpar os dados do perfil local e remover o código compilado gerado com base nesses dados (ou seja, para redefinir para o estado de instalação), execute o seguinte:

adb shell pm compile --reset 

Observação: esse comando não remove o código compilado gerado de dados de perfil externos (`.dm`) instalados com o app.

Para limpar todo o código compilado, execute este comando:

adb shell cmd package compile -m verify -f 

Observação: esse comando retém os dados do perfil local.