JIT-оптимизация и отладка

Проще всего выполнять отладку кода, когда он НЕ оптимизирован. Когда код оптимизирован, компилятор и среда выполнения вносят изменения в выпущенный код ЦП, поэтому он выполняется быстрее, но имеет не такое прямое сопоставление с начальным исходным кодом. Если сопоставление менее прямое, отладчикам часто не удается определить значения локальных переменных и пошаговое выполнение кода и точки останова могут не работать должным образом.

Примечание.

Дополнительные сведения о JIT-отладке см. в этой документации.

Принцип действия оптимизации в .NET

Как правило, конфигурация сборки "Выпуск" создает оптимизированный код, а конфигурация сборки "Отладка" — нет. Свойство MSBuild Optimize определяет, нужно ли компилятору оптимизировать код.

В экосистеме .NET код преобразуется из исходного в инструкции ЦП в два этапа: сначала компилятор C# преобразует введенный текст в промежуточную двоичную форму, называемую MSIL, и записывает код MSIL в DLL-файлы. Затем среда выполнения .NET преобразует этот код MSIL в инструкции ЦП. Оба действия можно оптимизировать до некоторой степени, но второй шаг, выполняемый средой выполнения .NET, осуществляет более значительные оптимизации.

Параметр "Отключать JIT-оптимизацию при загрузке модуля (только управляемый код)"

Отладчик предоставляет параметр, который управляет тем, что происходит, когда библиотека DLL, скомпилированная с включенной оптимизацией, загружается внутри целевого процесса. Если этот флажок не установлен (состояние по умолчанию), то, когда среда выполнения .NET компилирует код MSIL в код CPU, оптимизация остается включенной. Если флажок установлен, отладчик запрашивает отключение оптимизации.

Чтобы найти параметр Отключать JIT-оптимизацию при загрузке модуля (только управляемый код), щелкните Сервис>Параметры, а затем выберите страницу Общие в узле Отладка.

Отключение JIT-оптимизации

Когда следует включить параметр "Отключать JIT-оптимизацию"?

Установите этот флажок, если вы скачали библиотеки DLL из другого источника, например пакета NuGet, и хотите отладить код в этой библиотеке DLL. Чтобы отключение вступило в силу, необходимо также найти файл символов (PDB) для этой библиотеки DLL.

Если вас интересует отладка только локально создаваемого кода, лучше оставить этот флажок снятым, так как в некоторых случаях включение этого параметра значительно замедляет отладку. Для этого имеются две причины.

  • Оптимизированный код выполняется быстрее. Если вы отключаете оптимизацию для большей части кода, это может повлиять на производительность.
  • Если включен только пользовательский код, отладчик даже не будет пытаться загружать символы для оптимизированных DLL. Поиск символов может занять много времени.

Ограничения для использования параметра "Отключать JIT-оптимизацию"

Существует две ситуации, когда включение этого параметра НЕ работает.

  1. В ситуациях, когда вы присоединяете отладчик к уже выполняющемуся процессу, этот параметр не влияет на модули, которые уже были загружены во время подключения отладчика.

  2. Этот параметр не влияет на библиотеки DLL, которые были предварительно скомпилированы (или ngen'ed) в машинном коде. Однако использование предварительно скомпилированного кода можно отключить, запустив процесс с переменной среды COMPlus_ReadyToRun со значением 0. Это укажет среде выполнения .NET Core на необходимость отключения использования предварительно скомпилированных образов и приведет к принудительной JIT-компиляции кода платформы.

    Если вы используете .NET Framework, добавьте переменную среды COMPlus_ZapDisable и задайте для нее значение 1.

Задайте "COMPlus_ReadyToRun": "0", добавив его в каждый профиль в файле 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"
    }
  }
}