Unity .NET и Mono — галопом по компонентам
Полистал курсы от коробок навыков, мозгов гика и даже Великого Романа Сакутина и не нашел ответа на дефолтный вопрос с джуновых собеседований: «Что же такое .NET, Mono, компилятор, рантайм и прочие ругательства»
Справедливости ради, там эти ответы и не обязаны быть. Курсы дают всего лишь более или менее общий набор знаний, который каждый применяет как хочет. Также большинство из них и не дают навыков и знаний для поиска работы, в чем и кроется моя главная претензия к курсам. «Возьми кредит на 200к и получи дефолтные знания».
Также этот вопрос в большинстве случаев не несет никакой пользы во время работы. До тех пор пока ты не начинаешь залезать в низкоуровневые оптимизации или писать сотни тэгов над компонентами в морпехе.
1000 и 1 атрибут в морпехе
P.S. ничего не имею против морпеха, наоборот считаю самым удобным ECS фреймворком, но когда создаешь новые компоненты не через их контекстные кнопки, то приходится лезть в другие компоненты и копипастить тэги. Пока не догадаешься сделать темплейты в райдере для этого))
Но если вернуться к теме поиска работы, то вопрос про платформу и ее компоненты часто ставит начинающих разработчиков в тупик. Где-то на подкорке существует отдаленное понимание что такое компилятор и рантайм. Но формализовать это знание в четкий ответ рекрутеру, да если еще и волнуешься на первых собеседованиях… Целое дело
Поэтому давайте кратко пробежимся по компонентам .NET и Mono платформ, что у них общего и различного и для чего каждый компонент нужен.
Также в конце приложу ссылки для тех кому интересней копнуть в одну из тем более подробно.
Перед тем как начать, можешь подписаться на мой канал чтобы узнавать побольше интересного об играх и их разработке. Или записаться на менторство если и сам хочешь начать их делать за хорошие деньги
.NET
Согласно dotnet.microsoft.com ».NET — это бесплатная платформа приложений с открытым кодом, поддерживаемая корпорацией Майкрософт.»
Если чуть раскрыть формулировку, то это набор компонентов, которые позволяют нам писать приложения и собирать их под разные устройства. В нее входит абсолютно все: язык, его библиотеки, компиляторы (да, там больше одного), рантайм и сборщик мусора.
Первая версия .NET Framework была создана в 2002, а первая версия Unity — в 2005. Отсюда резонный вопрос, почему Unity не работает целиком на .NET
В то время, .NET был ориентирован только создание приложений под Windows. И для движка ориентированного на любые платформы это было критичным. Соответственно юнитеки (Unity Technologies) подобрали реализацию такой же платформы от компании Xamarin, которая в то же время развивала собственное решение для разработки приложения — платформу Mono
Mono забрала из .NET язык и его базовые библиотеки (знакомые нам по неймспейсу System), а остальные компоненты такие как компилятор, рантайм, сборщик мусора переписала под свои нужны
Важной частью реализации была поддержка AOT (ahead of time) компиляции, которая в то время отсутствовала в .NET. А это было немаловажно для того же самого IOS, в котором жит компиляция запрещена (из соображений безопасности).
Также были преимущества в виде наличия библиотек для работы с мобильными устройствами, их сенсорами, камерами геолокацией, разными графическими библиотеками и возможностью работы на процессорах с разными архитектурами. Ведь .NET в то время ориентировалась на классические х86/х64
Компоненты
Рассмотрим основные компоненты платформ и для чего они нужны
Компилятор — это программа, которая переводит исходный код, написанный на языке программирования высокого уровня (в нашем случае, C#), в машинный код, который может быть выполнен компьютером. Этот процесс называется компиляцией.
Язык, в который компилируется наш C# называется Intermediate Language или просто IL. В контексте реализаций платформ, и .NET и Mono самостоятельно реализовали этот язык. Но обе версии полностью соответствуют определенному стандарту настолько, что любая версия может выполнятся на любой платформе.
Дальше в бой вступает такая штука как рантайм. В .NET он называется CLR (или Common Language Runtime), в Mono — просто Mono runtime.
И он выполняет кучу всего с нашим il кодом:
компиляция в машинный код для целевого устройства. В зависимости от целевого устройства он может делать это прямо во время выполнения кода (т.н. JIT или Just in time компиляция) или заранее скомпилирует весь код для устройств где такая компиляция запрещена (AOT). То есть в первую очередь рантайм включает в себя набор компиляторов под все целевые платформы, а также дополнительные инструменты для такой компиляции (например, IL2CPP, про него позднее)
управление памятью, которым занимается всеми известный сборщик мусора
и куча других вещей типа обработки исключений, управление потоками, взаимодействие с неуправляемым кодом, проверка кода на безопасность и тд
Рассмотрим пару его компонентов:
IL2CPP
Средство для компиляции кода для устройств, поддерживающих только AOT компиляцию.
Как и следует из названия, этот инструмент переводит код из IL в C++, чтобы в последствии при помощи компилятора конкретной платформы.
Зачем он нужен? Да банально для того чтобы юнитекам не приходилось писать собственные компиляторы и можно было использовать стандартные компиляторы для целевых платформ которые давным-давно написаны.
Сборщик мусора
Его основная задача — освобождать память, занятую объектами, которые больше не используются, чтобы предотвратить утечки памяти и освободить ресурсы устройства для создания новых объектов.
Какие есть основные особенности у сборщика мусора в .NET:
поколения, которые позволяют выполнять сборку мусора быстрее. Если кратко, то существует 3 поколения в которые попадают объекты от наиболее быстроживущих до долгоживущих, которые проверяются на необходимость удаления реже.
компактирование памяти — после сборки мусора у вас может остаться множество разбросанных по всей памяти объектов. И такое их хаотичное расположение может послужить проблемам. Например, что большие объекты могут не найти себе места в памяти, ведь раз текущие объекты разбросаны, то между ними не окажется достаточно много места для нового.
Хотя Mono поставляется сразу с двумя сборщиками мусора, Unity использует только один из них — boehm или bdw gc, более старый, но при этом более легковесный что важно для тех же мобильных платформ.
В нем отсутствуют вышеперечисленные фишки, но зато существует так называемся инкрементальная сборка, которая позволяет размазывать процесс сборки на несколько кадров.
Также оба сборщика немного отличаются по своему принципу работы.
Верхнеуровнево они оба анализируют стек и глобальные объекты на предмет ссылок на объекты в куче, а потом и остальные объекты на наличие прочих ссылок. Те, на которые по итоге не ведут никакие ссылки, помечаются для удаления.
Но .NET сборщик мусора всегда точно знает какие объекты памяти являются ссылками на другие объекты, тогда как boehm анализирует все объекты в памяти которые потенциально могут быть ссылками на объект. Поэтому такой сборщик потенциально может оставлять в памяти объекты, на которые по итогу и не существует ни одной ссылки. То есть если в вашем объекте есть int поле которое по значению совпадает ссылкой на какой-то объект, то этот объект не удалится.
P.S. Дополнительная инфа про GC для заинтересованных прилинкована внизу статьи
Штош, таким образом мы примерно представляем как устроена Mono и .NET и сможем ответить на этот вопрос на собесе (в остальном это все и нахуй не надо)
Подписывайтесь на канал чтобы узнавать еще больше и делать хорошие игры за хорошие деньги
Спасибо!
Дополнительная информация о GC:
Серия постов как работает GC в Unity под капотом
Всего лишь статья из Википедии, но тоже довольно подробная
Статья от My.Games про GC