Otimização e depuração JIT

Se você estiver tentando depurar o código, será mais fácil quando esse código NÃO for otimizado. Quando o código é otimizado, o compilador e o runtime fazem alterações no código de CPU emitido para que ele seja executado mais rapidamente, mas tenha um mapeamento menos direto para o código-fonte original. Se o mapeamento for menos direto, os depuradores frequentemente não poderão informar o valor das variáveis locais e os pontos de interrupção e de etapa de código poderão não funcionar conforme o esperado.

Observação

Para obter mais informações sobre a depuração JIT (Just-In-Time), leia esta documentação.

Como as otimizações funcionam no .NET

Normalmente, a configuração de build de versão cria código otimizado, o que não acontece na configuração de build de depuração. A propriedade MSBuild Optimize controla se o compilador é orientado a otimizar o código.

No ecossistema do .NET, o código é transformado da origem para as instruções da CPU em um processo de duas etapas: primeiro, o compilador C# converte o texto que você digita em um formulário binário intermediário chamado MSIL e grava o MSIL para arquivos .dll. Posteriormente, o Runtime do .NET converte essa MSIL em instruções de CPU. Ambas as etapas podem ser otimizadas até certo ponto, mas a segunda etapa executada pelo Runtime do .NET executa as otimizações mais significativas.

A opção 'Suprimir otimização JIT no carregamento do módulo (somente gerenciado)'

O depurador expõe uma opção que controla o que acontece quando uma DLL compilada com otimizações habilitadas carrega dentro do processo de destino. Se essa opção estiver desmarcada (o estado padrão), quando o Runtime do .NET compilar o código MSIL no código da CPU, ela deixará as otimizações habilitadas. Se a opção for verificada, o depurador solicitará que as otimizações sejam desabilitadas.

Para localizar a opção Suprimir otimização JIT no carregamento do módulo (somente gerenciado), selecione Ferramentas>Opções e, em seguida, selecione a página Geral no nó Depuração.

Suprimir otimização JIT

Quando você deve verificar a opção 'Suprimir otimização JIT'?

Verifique essa opção quando você baixou as DLLs de outra fonte, como um pacote nuget, e deseja depurar o código nesta DLL. Para que a supressão funcione, você também deve encontrar o arquivo de símbolo (.pdb) para essa DLL.

Se você estiver interessado apenas em depurar o código que está criando localmente, é melhor deixar essa opção desmarcada, pois, em alguns casos, habilitar essa opção reduzirá significativamente a depuração. Há dois motivos para essa redução:

  • O código otimizado é executado mais rapidamente. Se você estiver desativando otimizações para muitos códigos, o impacto no desempenho poderá ser somado.
  • Se você tiver Apenas Meu Código habilitado, o depurador nem tentará carregar símbolos para DLLs otimizadas. Localizar símbolos pode levar muito tempo.

Limitações da opção 'Suprimir otimização JIT'

Há duas situações em que ativar essa opção NÃO funcionará:

  1. Em situações em que você está anexando o depurador a um processo já em execução, essa opção não terá efeito sobre os módulos que já estavam carregados no momento em que o depurador foi anexado.

  2. Essa opção não tem efeito em DLLs que foram compiladas previamente (ou ngen’ed) no código nativo. No entanto, você pode desabilitar o uso de código pré-compilado iniciando o processo com a variável de ambiente 'COMPlus_ReadyToRun' definida como '0'. Isso instruirá o runtime do .NET Core a desabilitar o uso de imagens pré-compiladas, forçando o runtime a compilar código da estrutura JIT.

    Se você estiver direcionando o .NET Framework, adicione a variável de ambiente 'COMPlus_ZapDisable' e defina-a como '1'.

Defina "COMPlus_ReadyToRun": "0" adicionando-o a cada perfil no arquivo Properties\launchSettings.json:

{
  "iisSettings": {
    "windowsAuthentication": false,
    "anonymousAuthentication": true,
    "iisExpress": {
      "applicationUrl": "http://localhost:59694/",
      "sslPort": 44320
    }
  },
  "profiles": {
    "IIS Express": {
      "commandName": "IISExpress",
      "launchBrowser": true,
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development",
        "COMPlus_ReadyToRun": "0"
      }
    },
    "HttpLoggingSample": {
      "commandName": "Project",
      "launchBrowser": true,
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development",
        "COMPlus_ReadyToRun": "0"
      },
      "applicationUrl": "https://localhost:5001;http://localhost:5000"
    }
  }
}