...

понедельник, 13 апреля 2015 г.

Сломанный legacy JIT в .NET 4.6

Сегодня я расскажу вам об одной неприятной ситуации, которая связана с JIT в .NET 4.6. Вот несколько фактов:

  • Если вы поставили .NET Framework 4.6 Preview, то у вас по дефолту стоит RyuJIT.

  • Если вы поставили Visual Studio 2015 CTP, то она включает .NET Framework 4.6 Preview, а значит у вас по дефолту стоит RyuJIT.

  • Если вы работаете на Windows 10 Tech Preview, то она также включает.NET Framework 4.6 Preview, а значит у вас по дефолту стоит RyuJIT.

  • Если вы хотите вернуть старый JIT, то это можно сделать с помощью ключа регистра, переменной среды или app.config-настройки useLegacyJit.

  • Если включить useLegacyJit в Windows 8 или Windows 8.1, то вы получите большое количество проблем, связанных с компиляцией и запуском приложений.

  • RyuJIT всё ещё не готов к реальному использованию, некоторые программы могут работать некорректно на нём.


Возможно, я просто что-то не понимаю в этой жизни. Давайте разберёмся в ситуации вместе.

Обнаружение проблемы




Не так давно я занимался исследованием особенностей различных версий JIT в .NET. В какой-то момент я обратил внимание на то, что ASM-код для 64-битной версии программы не похож на старый JIT-x64. Вместо этого он был похож на результат работы RyuJIT. Я не очень люблю RyuJIT: в нём нет многих оптимизаций, а код зачастую исполняется дольше. Я проверил ключ регистра HKLM\SOFTWARE\Microsoft\.NETFramework\AltJit и переменную среды COMPLUS_AltJit: всё было нормально, RyuJIT должен был выключен. Я проверил версию JIT своим любимым способом: действительно, код обрабатывается с помощью RyuJIT. Тогда я полез в гугл и узнал кое-что новое: при установке .NET Framework 4.6 Preview вы совершенно бесплатно получаете RyuJIT в качестве дефолта (на моём компьютере установка произошла вместе с Visual Studio 2015). При этом существует три способа вернуть всё на место:

  1. Установить переменную среды COMPLUS_useLegacyJit=1

  2. Установить ключ регистра useLegacyJit=1 (REG_WORD) в HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework или HKEY_CURRENT_USER\SOFTWARE\Microsoft\.NETFramework

  3. В app.config-файле прописать волшебные строчки:

    <configuration>
    <runtime>
    <useLegacyJit enabled="1">
    </runtime>
    </configuration>





Ок, давайте попробуем. Действительно, способ рабочий, он возвращает старый JIT на место, но вот только при этом портит разные полезные штуки. Несколько примеров:

  1. Самое воспроизводимое: вызов GC.Collect() падает с исключением (чтобы всё было правильно не забудьте поставить Platform Target: x64, Target framework: .NET 4+).


  2. csc2 плюётся страшными кодами выхода.


  3. Постоянно вылетающий mscorlib recursive resource lookup bug.


  4. Многие приложения падают на старте (например, dotMemory).





В остальном при большом желании работать можно, но постоянные ошибки очень мешают. Пригорюнился я, да и выключил useLegacyJit. «Будем жить с новым RyuJIT, что поделать-то» — сказал я себе.

Но на этом мои проблемы не закончились. На днях я решил воспользоваться одной из .NET-утилит в проекте на своей работе. А она упала. Падение отлично воспроизводилось. Как порядочный разработчик, я пошёл и завёл баг в JIRA. Вскоре тикет был закрыт со статусом Cannot Reproduce: у всех всё работало, кроме меня. «Хм…» — подумал я. Пошёл в реестр, включил useLegacyJit, снова запустил утилиту — всё отработало на отличненько. Расследование бага всё ещё ведётся, но факт остаётся фактом: RyuJIT портил нормальную работу нашей замечательной утилитки.


И тогда я разозлился. «Да не так уж мне и нужен этот .NET 4.6» — подумал я. И снёс его вместе с Visual Studio 2015. Проверяю: RyuJIT на месте. Я пошёл в установку и удаление программ и снёс всё, что шло вместе с .NET 4.6. Проверяю: RyuJIT на месте. Тогда я совсем разозлился: начал сносить вообще всё, что в своём названии содержало «Microsoft» или «.NET». Проверяю: RyuJIT на месте. Я пошёл на диск C: и начал руками удалять всё, посвящённое .NET, что вообще удалялось. До конца мне .NET снести не удалось, поэтому я прошёлся по системным настройкам и повыключал все выключаемые Windows-компоненты, связанные с .NET. После всех процедур делаю последнюю проверку: RyuJIT на месте.


Воспроизведение проблемы




Жить на руинах системы было не очень весело, поставить все .NET-штуки заново оказалось затруднительно, поэтому я начал процесс восстановления системы. Откатился к заводским настройкам, поставил всё программы, настроил рабочее окружение и кинулся проверять работу GC.Collect(): старый добрый Jit-x64 на месте, сборка мусора работает нормально. Я уже предвидел результат, но экспериментатор в моей душе заставил меня поставить Visual Studio 2015 (включая .NET 4.6 и дефолтный RyuJIT). Прогнал все свои тесты, результат не поменялся: моя .NET-утилитка не работала под RyuJIT, а useLegacyJit кидался ошибками на каждый мой шаг.

«Может у меня Windows какой-то дефектный» — подумал я. Переходим к следующему этапу: я нашёл в интернете образы чистых Windows 8 и Windows 8.1, поставил их под виртуалкой. На новенькие системы мной была установлена Visual Studio 2015 CTP6 Ultimate (минимальная конфигурация, без всяких дополнительных опций). Проводим эксперимент: собираем консольное x64-приложение с единственным вызовом GC.Collect(), включаем useLegacyJIT, запускаем и видим, как приложение плюётся исключением прямо нам в лицо.


Далее я поставил под виртуалкой Window 10 Tech Preview. Меня ждало ещё одно открытие: там .NET 4.6 встроенный, RyuJIT сразу идёт по дефолту. Порадовало одно: опция useLegacyJit работает нормально, никаких исключений не наблюдается. А вот без неё на дефолтном RyuJIT моя .NET утилитка всё ещё продолжает падать (обязательно разберусь в чём же там дело, увы, это не так просто).


Заключение




Мне всё ещё кажется, что я просто что-то не понимаю об этой жизни и что-то не так делаю. Я написал этот пост, т. к. мне кажется, что кто-нибудь ещё также может что-то не понять и наступить на те же грабли. Эксперименты проводились на моём рабочем ноутбуке и под виртуалками: мне этого недостаточно, чтобы объявить, что всё действительно плохо. Буду признателен всем, кто проверит ситуацию у себя на машине и отпишется о результатах. Если кто-то разбирается в ситуации лучше меня, то большая просьба рассказать кто виноват и что делать.

Ссылки




This entry passed through the Full-Text RSS service - if this is your content and you're reading it on someone else's site, please read the FAQ at http://fivefilters.org/content-only/faq.php#publishers.


Комментариев нет:

Отправить комментарий