- PVSM.RU - https://www.pvsm.ru -
Сегодня я расскажу вам об одной неприятной ситуации, которая связана с JIT в .NET 4.6. Вот несколько фактов:
useLegacyJit
.useLegacyJit
в Windows 8 или Windows 8.1, то вы получите большое количество проблем, связанных с компиляцией и запуском приложений.Возможно, я просто что-то не понимаю в этой жизни. Давайте разберёмся в ситуации вместе.
Не так давно я занимался исследованием особенностей различных версий JIT в .NET. В какой-то момент я обратил внимание на то, что ASM-код для 64-битной версии программы не похож на старый JIT-x64. Вместо этого он был похож на результат работы RyuJIT. Я не очень люблю RyuJIT: в нём нет многих оптимизаций, а код зачастую исполняется дольше. Я проверил ключ регистра HKLMSOFTWAREMicrosoft.NETFrameworkAltJit
и переменную среды COMPLUS_AltJit
: всё было нормально, RyuJIT должен был выключен. Я проверил версию JIT своим любимым способом [1]: действительно, код обрабатывается с помощью RyuJIT. Тогда я полез в гугл и узнал кое-что новое [2]: при установке .NET Framework 4.6 Preview вы совершенно бесплатно получаете RyuJIT в качестве дефолта (на моём компьютере установка произошла вместе с Visual Studio 2015). При этом существует три способа вернуть всё на место:
COMPLUS_useLegacyJit=1
useLegacyJit=1
(REG_WORD
) в HKEY_LOCAL_MACHINESOFTWAREMicrosoft.NETFramework
или HKEY_CURRENT_USERSOFTWAREMicrosoft.NETFramework
app.config
-файле прописать волшебные строчки:
<configuration>
<runtime>
<useLegacyJit enabled="1">
</runtime>
</configuration>
Ок, давайте попробуем. Действительно, способ рабочий, он возвращает старый JIT на место, но вот только при этом портит разные полезные штуки. Несколько примеров:
GC.Collect()
падает с исключением (чтобы всё было правильно не забудьте поставить Platform Target: x64, Target framework: .NET 4+).
В остальном при большом желании работать можно, но постоянные ошибки очень мешают. Пригорюнился я, да и выключил 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 утилитка всё ещё продолжает падать (обязательно разберусь в чём же там дело, увы, это не так просто).
Мне всё ещё кажется, что я просто что-то не понимаю об этой жизни и что-то не так делаю. Я написал этот пост, т. к. мне кажется, что кто-нибудь ещё также может что-то не понять и наступить на те же грабли. Эксперименты проводились на моём рабочем ноутбуке и под виртуалками: мне этого недостаточно, чтобы объявить, что всё действительно плохо. Буду признателен всем, кто проверит ситуацию у себя на машине и отпишется о результатах. Если кто-то разбирается в ситуации лучше меня, то большая просьба рассказать кто виноват и что делать.
Автор: DreamWalker
Источник [5]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/c-2/88645
Ссылки в тексте:
[1] своим любимым способом: http://aakinshin.net/ru/blog/dotnet/jit-version-determining-in-runtime/
[2] кое-что новое: https://github.com/Microsoft/dotnet/blob/master/docs/testing-with-ryujit.md
[3] Microsoft .NET Framework 4.6 Preview (Web Installer): http://www.microsoft.com/en-us/download/details.aspx?id=44928
[4] Visual Studio 2015 CTPs: https://www.visualstudio.com/en-us/downloads/visual-studio-2015-ctp-vs.aspx
[5] Источник: http://habrahabr.ru/post/255567/
Нажмите здесь для печати.