#код #unirx
Друзья, приветствую 👋
Иногда в реактивном программировании необходимо не просто выполнить какую-либо функцию, а дождаться её выполнения и получить результат.
В текущем году данный вопрос был наиболее частым среди моих коллег.
Приведу пример:
В UniRx, к сожалению, такое поведение отсутствует.
❗Честно скажу, что в своих проектах, я обходил стороной такой подход, и до сих пор считаю, что если такое назревает, то с архитектурой проекта МОЖЕТ быть что-то не так.
Тем не менее, если вы всё спроектировали хорошо, но такая потребность присутствует, то это как раз тот вариант, когда вам может это пригодиться.
Тк запрос был частым, я решил немного доработать код ReactiveCommand из UniRx и выложить сюда.
Чтобы не ломать codestyle, который используется в UniRx, писал в их стиле.
Как пользоваться и осноные нюансы:
❗Если вызвать Dispose для команды, то при попытке сделать Execute будет выбрасываться исключение: ObjectDisposedException: Cannot access a disposed object.
❗Если вызвать Dispose для команды, то при попытке сделать Subscribe будет выбрасываться исключение: ObjectDisposedException: Cannot access a disposed object.
❗Если вызвать Dispose для подписки, то обработчик больше не будет срабатывать
❗Если несколько раз подписаться на команду, то будет срабатывать последняя подписка, поэтому лучше избегать ситуацию с несколькими подписками.
Файл можно скачать ниже👇
Всем хороших выходных!
Друзья, приветствую 👋
Иногда в реактивном программировании необходимо не просто выполнить какую-либо функцию, а дождаться её выполнения и получить результат.
В текущем году данный вопрос был наиболее частым среди моих коллег.
Приведу пример:
ReactiveCommand<string, string> testStringResultCommand = new ReactiveCommand<string, string>();
testStringResultCommand.Subscribe(inputValue =>
{
return $"{inputValue}def";
});
string resultNormal = testStringResultCommand.Execute("abc");
Debug.Log(resultNormal); <- abcdef
testStringResultCommand.Dispose();
В UniRx, к сожалению, такое поведение отсутствует.
❗Честно скажу, что в своих проектах, я обходил стороной такой подход, и до сих пор считаю, что если такое назревает, то с архитектурой проекта МОЖЕТ быть что-то не так.
Тем не менее, если вы всё спроектировали хорошо, но такая потребность присутствует, то это как раз тот вариант, когда вам может это пригодиться.
Тк запрос был частым, я решил немного доработать код ReactiveCommand из UniRx и выложить сюда.
Чтобы не ломать codestyle, который используется в UniRx, писал в их стиле.
Как пользоваться и осноные нюансы:
ReactiveCommand<string, string> testStringResultCommand = new ReactiveCommand<string, string>();
testStringResultCommand.Subscribe(inputValue =>
{
return $"{inputValue}def";
});
string resultNormal = testStringResultCommand.Execute("abc");
Debug.Log(resultNormal); <- abcdef
testStringResultCommand.Dispose();
string resultDisposed = testStringResultCommand.Execute("abc"); <- ObjectDisposedException: Cannot access a disposed object.
❗Если вызвать Dispose для команды, то при попытке сделать Execute будет выбрасываться исключение: ObjectDisposedException: Cannot access a disposed object.
❗Если вызвать Dispose для команды, то при попытке сделать Subscribe будет выбрасываться исключение: ObjectDisposedException: Cannot access a disposed object.
❗Если вызвать Dispose для подписки, то обработчик больше не будет срабатывать
❗Если несколько раз подписаться на команду, то будет срабатывать последняя подписка, поэтому лучше избегать ситуацию с несколькими подписками.
Файл можно скачать ниже👇
Всем хороших выходных!
Приветствую 👋
Хочу поделиться ближайшими планами.
По мотивам вопроса с кубиком я решил написать упрощенный код и сделать его разбор.
Далее при наличии достаточного количества желающих можем запланировать и провести видеострим.
Для понимания запроса просьба поставить реакцию всем, кто хотел бы присутствовать.
Хорошего вечера.
Хочу поделиться ближайшими планами.
По мотивам вопроса с кубиком я решил написать упрощенный код и сделать его разбор.
Далее при наличии достаточного количества желающих можем запланировать и провести видеострим.
Для понимания запроса просьба поставить реакцию всем, кто хотел бы присутствовать.
Хорошего вечера.
Приветствую, друзья 👋
Код для игрового кубика написан 💪
Разбор в процессе!
Позже будет полезный пост по Rider, как настроить автоматическое удаление ненужных "using".
Код для игрового кубика написан 💪
Разбор в процессе!
Позже будет полезный пост по Rider, как настроить автоматическое удаление ненужных "using".
Media is too big
VIEW IN TELEGRAM
#разбор_кода #unity #архитектура
Приветствую 👋
Я завершил разбор кода для игры с кубиками 🥳.
Видео доступно по ссылке ➡️
https://www.youtube.com/watch?v=xikR6XkeuKE
Приятного просмотра 😉
Приветствую 👋
Я завершил разбор кода для игры с кубиками 🥳.
Видео доступно по ссылке ➡️
https://www.youtube.com/watch?v=xikR6XkeuKE
Приятного просмотра 😉
YouTube
Геймдев. Разбор архитектурного подхода на примере игры для канала https://t.me/gamedev_unity3d
Разбор подхода к проектированию архитектуры игрового проекта в рамках образовательного канала по разработке игр на Unity 3D.
Разбираем:
- точка входа в код
- слои абстракции
- префабы и их организация
- жизненный цикл объектов.
Больше полезной информации…
Разбираем:
- точка входа в код
- слои абстракции
- префабы и их организация
- жизненный цикл объектов.
Больше полезной информации…
Приветствую, друзья👋 Как вы? Удалось посмотреть разбор и подготовить список вопросов?
Отдайте свой голос, какой из вариантов по стриму для вас более привлекателен 👇
Отдайте свой голос, какой из вариантов по стриму для вас более привлекателен 👇
Anonymous Poll
19%
Будни после 19:00 Мск
22%
Выходной
22%
НГ каникулы 🎄🥂🍾
36%
Любой из вариантов
Друзья, с наступающим Новым Годом 🥂🍾
Пусть он принесет вам рост и новые возможности 🙌
С 2024 годом 🎄
Пусть он принесет вам рост и новые возможности 🙌
С 2024 годом 🎄
Друзья, приветствую 👋
К сожалению, в связи с высокой загруженностью материал на канале появляется не с той частотой, как мне хотелось 😔
Из приятного: на текущий момент готовлю для вас статью, посвященную различию между реактивными объектами и делегатами ✍️.
Обещанный стрим постараюсь поставить на 17 - 18 февраля.
Хорошего дня!
К сожалению, в связи с высокой загруженностью материал на канале появляется не с той частотой, как мне хотелось 😔
Из приятного: на текущий момент готовлю для вас статью, посвященную различию между реактивными объектами и делегатами ✍️.
Обещанный стрим постараюсь поставить на 17 - 18 февраля.
Хорошего дня!
Друзья, приветствую 👋 Я часто слышал аргумент: "Зачем реактивщина, ведь тоже самое можно сделать на делегатах". Пока я готовлю статью на эту тему, предлагаю рассмотреть пример (код в комментарии) и выбрать ответ.
Final Results
71%
Все ок, сработают две подписки, т.к. делегат - это ref тип
21%
Не ок, делегат - это value тип, вторая подписка не сработает
8%
Свой вариант ответа
Приветствую 👋
Стрим планируем на это воскресенье (18.02) 16:00 Мск
Буду раз всех вас видеть
Стрим планируем на это воскресенье (18.02) 16:00 Мск
Буду раз всех вас видеть
Всем привет, напоминаю, что через 45 мин начинаем стрим, стрим будет проходить в этом канале.
#архитектура #делегаты #event #action #Unity3D
Реактивное программирование vs делегаты в C#, Unity 3D
Приветствую 👋
Сегодня говорим про реактивное программирование vs делегаты (delegate) в C#, Unity 3D.
Для начала поясню, почему в статье я рассматриваю именно delegate, а не event или Action.
В C# Action, event и delegate являются ключевыми элементами, используемыми для работы с методами как с объектами. Это позволяет реализовывать такие концепции, как обратные вызовы (callbacks) и событийно-ориентированное программирование.
Delegate является основой для Action и event, где
- Action предоставляет удобный способ использования делегатов без возвращаемого значения
- event использует делегаты, обеспечивая контролируемый способ подписки на уведомления и обработки событий.
Поэтому в статье я буду рассматривать именно delegate.
Но для начала приведу основные отличия delegate, Action, event:
- Delegate - это тип, который представляет ссылки на методы с определённой сигнатурой и возвращаемым типом.
Это означает, что мы можем использовать переменные delegate для хранения ссылок на методы.
Delegate обеспечивает возможность передачи методов как аргументов методам или в качестве типов возвращаемых значений.
Delegate поддерживает многоадресные вызовы, позволяя вызывать несколько методов подписанных на делегат (multicast делегаты).
- Action - это обобщённый делегат, который не возвращает значение (возвращаемый тип void) и может принимать от 0 до 16 параметров.
Action является удобным способом использования делегатов, не требуя объявлять новый тип делегата для каждой сигнатуры метода.
По сути, Action предназначен для ситуаций, когда нужно передать методы, не возвращающие значение.
- Event - это способ, с помощью которого класс или объект может предоставлять уведомления.
Итак event (события):
-используют делегаты для обработки уведомлений.
- реализует паттерн Observer, где издатель уведомляет подписчиков о том, что произошло определённое событие.
- ограничивают способность внешнего кода вызывать делегат. Внешний код может подписаться на событие или отписаться от него, но не может напрямую вызвать делегат события.
- добавляют уровень инкапсуляции к делегатам, обеспечивая более безопасную и управляемую модель подписки на уведомления.
❗Реактивное программирование и использование делегатов в C# представляют собой два различных, но похожих подхода к обработке и передаче данных.
Оба механизма имеют свои преимущества и недостатки, и выбор между ними зависит от конкретных требований к проекту.
продолжение 🔽
Реактивное программирование vs делегаты в C#, Unity 3D
Приветствую 👋
Сегодня говорим про реактивное программирование vs делегаты (delegate) в C#, Unity 3D.
Для начала поясню, почему в статье я рассматриваю именно delegate, а не event или Action.
В C# Action, event и delegate являются ключевыми элементами, используемыми для работы с методами как с объектами. Это позволяет реализовывать такие концепции, как обратные вызовы (callbacks) и событийно-ориентированное программирование.
Delegate является основой для Action и event, где
- Action предоставляет удобный способ использования делегатов без возвращаемого значения
- event использует делегаты, обеспечивая контролируемый способ подписки на уведомления и обработки событий.
Поэтому в статье я буду рассматривать именно delegate.
Но для начала приведу основные отличия delegate, Action, event:
- Delegate - это тип, который представляет ссылки на методы с определённой сигнатурой и возвращаемым типом.
Это означает, что мы можем использовать переменные delegate для хранения ссылок на методы.
Delegate обеспечивает возможность передачи методов как аргументов методам или в качестве типов возвращаемых значений.
Delegate поддерживает многоадресные вызовы, позволяя вызывать несколько методов подписанных на делегат (multicast делегаты).
- Action - это обобщённый делегат, который не возвращает значение (возвращаемый тип void) и может принимать от 0 до 16 параметров.
Action является удобным способом использования делегатов, не требуя объявлять новый тип делегата для каждой сигнатуры метода.
По сути, Action предназначен для ситуаций, когда нужно передать методы, не возвращающие значение.
- Event - это способ, с помощью которого класс или объект может предоставлять уведомления.
Итак event (события):
-используют делегаты для обработки уведомлений.
- реализует паттерн Observer, где издатель уведомляет подписчиков о том, что произошло определённое событие.
- ограничивают способность внешнего кода вызывать делегат. Внешний код может подписаться на событие или отписаться от него, но не может напрямую вызвать делегат события.
- добавляют уровень инкапсуляции к делегатам, обеспечивая более безопасную и управляемую модель подписки на уведомления.
❗Реактивное программирование и использование делегатов в C# представляют собой два различных, но похожих подхода к обработке и передаче данных.
Оба механизма имеют свои преимущества и недостатки, и выбор между ними зависит от конкретных требований к проекту.
продолжение 🔽
#архитектура #делегаты #event #action #Unity3D
Реактивное программирование vs делегаты в C#, Unity 3D продолжение 🔽
Рассмотрим ключевые моменты каждого подхода и выделим тонкости, связанные с делегатами.
Реактивное программирование - это парадигма, ориентированная на потоки данных и распространение изменений.
Это значит, что можно легко выразить статические или динамические потоки данных в программе, а также реагировать на их изменения.
Например, при изменении реактивных характеристик игрока в профиле, мы всегда можем подписаться на изменение нужных характеристик и сделать обработку детерминированной.
Также можно получить и использовать текущие значение реактивных характеристик, если этого требует наша логика.
В реактивном программировании необходимо помнить, как работает ReactiveProperty и ReactiveCommand. Краткий обзор.
При вдумчивом подходе в коде не будет никаких сюрпризов.
Вы сможете неразрывно писать код, даже когда логика требует выполнить реактивную команду и получить и обработать результат.
Подробнее тут.
Плюсы:
- Упрощение работы с потоками данных.
Реактивное программирование позволяет обрабатывать запросы, упрощая работу с потоками данных и их синхронизацию.
- Лучшая масштабируемость и отзывчивость.
Игры, написанные с использованием реактивного подхода, часто более отзывчивы и легче масштабируются благодаря эффективному управлению потоками данных.
Делегаты работают медленнее, когда выполняется множество подписок.
- Выразительность и лаконичность кода.
Реактивное программирование позволяет выражать сложные потоки данных и их взаимодействия более лаконично и наглядно.
Минусы:
- Для разработчиков может быть сложно освоить парадигму реактивного программирования и научиться думать в её категориях.
- Отладка реактивного подхода может быть более сложной, если мы будем задействовать асинхронщину.
Продолжение 🔽
Реактивное программирование vs делегаты в C#, Unity 3D продолжение 🔽
Рассмотрим ключевые моменты каждого подхода и выделим тонкости, связанные с делегатами.
Реактивное программирование - это парадигма, ориентированная на потоки данных и распространение изменений.
Это значит, что можно легко выразить статические или динамические потоки данных в программе, а также реагировать на их изменения.
Например, при изменении реактивных характеристик игрока в профиле, мы всегда можем подписаться на изменение нужных характеристик и сделать обработку детерминированной.
Также можно получить и использовать текущие значение реактивных характеристик, если этого требует наша логика.
В реактивном программировании необходимо помнить, как работает ReactiveProperty и ReactiveCommand. Краткий обзор.
При вдумчивом подходе в коде не будет никаких сюрпризов.
Вы сможете неразрывно писать код, даже когда логика требует выполнить реактивную команду и получить и обработать результат.
Подробнее тут.
Плюсы:
- Упрощение работы с потоками данных.
Реактивное программирование позволяет обрабатывать запросы, упрощая работу с потоками данных и их синхронизацию.
- Лучшая масштабируемость и отзывчивость.
Игры, написанные с использованием реактивного подхода, часто более отзывчивы и легче масштабируются благодаря эффективному управлению потоками данных.
Делегаты работают медленнее, когда выполняется множество подписок.
- Выразительность и лаконичность кода.
Реактивное программирование позволяет выражать сложные потоки данных и их взаимодействия более лаконично и наглядно.
Минусы:
- Для разработчиков может быть сложно освоить парадигму реактивного программирования и научиться думать в её категориях.
- Отладка реактивного подхода может быть более сложной, если мы будем задействовать асинхронщину.
Продолжение 🔽
#архитектура #делегаты #event #action #Unity3D
Реактивное программирование vs делегаты в C#, Unity 3D продолжение 🔽
Делегаты в C# - это типы, которые представляют собой ссылки на методы.
С их помощью можно передавать методы в качестве аргументов другим методам, что делает делегаты удобным средством для реализации обратных вызовов и событий.
Плюсы:
- Делегаты позволяют создавать гибкие и масштабируемые приложения благодаря возможности использования методов в качестве параметров.
- Multicast делегаты могут ссылаться сразу на несколько методов, что позволяет легко реализовывать паттерн Observer.
Минусы:
- Сложности с multicast делегатами.
Хотя multicast делегаты предоставляют мощные возможности, управление порядком вызова и обработка возвращаемых значений могут быть сложными.
- Ограниченность в сравнении с реактивным программированием.
Делегаты могут быть менее выразительными при работе с сложными потоками данных по сравнению с реактивным программированием.
- Неявные тонкости, которые могут запутать начинающих разработчиков.
Продолжение 🔽
Реактивное программирование vs делегаты в C#, Unity 3D продолжение 🔽
Делегаты в C# - это типы, которые представляют собой ссылки на методы.
С их помощью можно передавать методы в качестве аргументов другим методам, что делает делегаты удобным средством для реализации обратных вызовов и событий.
Плюсы:
- Делегаты позволяют создавать гибкие и масштабируемые приложения благодаря возможности использования методов в качестве параметров.
- Multicast делегаты могут ссылаться сразу на несколько методов, что позволяет легко реализовывать паттерн Observer.
Минусы:
- Сложности с multicast делегатами.
Хотя multicast делегаты предоставляют мощные возможности, управление порядком вызова и обработка возвращаемых значений могут быть сложными.
- Ограниченность в сравнении с реактивным программированием.
Делегаты могут быть менее выразительными при работе с сложными потоками данных по сравнению с реактивным программированием.
- Неявные тонкости, которые могут запутать начинающих разработчиков.
Продолжение 🔽
Теперь вернёмся к опросу
К сожалению, корректный корректно ответила меньшая часть опрашиваемых.
❗Поскольку делегат - это ref тип, большинство посчитало, что в вышеприведенном коде вторая подписка сработает после вызова dealDamage в методе PassDealDamageToAnotherLayer, но это не так.
Для понимания происходящего в коде, опишу принцип работы:
Когда мы передаём делегат dealDamage в метод PassDealDamageToAnotherLayer, происходит передача по значению.
Это означает, что внутри PassDealDamageToAnotherLayer используется копия ссылки на тот же список вызовов делегата, что и в оригинальном делегате dealDamage на момент передачи.
Все изменения, которые происходят с делегатом dealDamage после его передачи в PassDealDamageToAnotherLayer (например, добавление новых методов в список вызовов делегата),
не отражаются на копии, которая уже была передана и используется внутри метода PassDealDamageToAnotherLayer.
Продолжение 🔽
К сожалению, корректный корректно ответила меньшая часть опрашиваемых.
public class Root : BaseMonoBehaviour
{
private delegate void DealDamage();
private void Start()
{
// инстанцируем делегат с лямбдой - заглушкой
DealDamage dealDamage = () =>
{
Debug.Log("Deal damage stub");
};
// тут условно передаем делегат в слой, который отвечает за вызов делегата
PassDealDamageToAnotherLayer(dealDamage);
// подписываемся логикой на делегат
dealDamage += () =>
{
Debug.Log("Deal damage subscriber");
};
}
private void PassDealDamageToAnotherLayer(DealDamage dealDamage)
{
// через 5 секунд сделаем вызов делегата
Observable.Timer(TimeSpan.FromSeconds(5)).Subscribe(_ =>
{
dealDamage();
});
}
}
❗Поскольку делегат - это ref тип, большинство посчитало, что в вышеприведенном коде вторая подписка сработает после вызова dealDamage в методе PassDealDamageToAnotherLayer, но это не так.
Для понимания происходящего в коде, опишу принцип работы:
Когда мы передаём делегат dealDamage в метод PassDealDamageToAnotherLayer, происходит передача по значению.
Это означает, что внутри PassDealDamageToAnotherLayer используется копия ссылки на тот же список вызовов делегата, что и в оригинальном делегате dealDamage на момент передачи.
Все изменения, которые происходят с делегатом dealDamage после его передачи в PassDealDamageToAnotherLayer (например, добавление новых методов в список вызовов делегата),
не отражаются на копии, которая уже была передана и используется внутри метода PassDealDamageToAnotherLayer.
Продолжение 🔽
Чтобы решить данную проблему, небходимо либо перенести подписку на делегат до его передачи в PassDealDamageToAnotherLayer, либо изменить логику так, чтобы ссылка на делегат могла быть обновлена внутри PassDealDamageToAnotherLayer после добавления новых подписок.
Приведу пример альтернативной вариация корректно работающего кода, в котором ссылка на делегат обновляется постоянно:
Подытожу Выбор между реактивным программированием и делегатами в C# зависит от специфики задачи и глубины понимания каждого из подходов.
Реактивное программирование лучше подходит для игр, где важна работа с потоками данных и их обработка в реальном времени.
Делегаты предпочтительнее в ситуациях, где требуется гибкость в реализации обратных вызовов и событий.
Оба подхода имеют свои тонкости и сложности, особенно когда речь идет о multicast делегатах, что требует от разработчика глубокого понимания обоих механизмов для их эффективного использования.
Всем хороших выходных 🖐
Приведу пример альтернативной вариация корректно работающего кода, в котором ссылка на делегат обновляется постоянно:
public class Root : BaseMonoBehaviour
{
private delegate void DealDamage();
private DealDamage _dealDamage;
private void Start()
{
// инстанцируем делегат с лямбдой - заглушкой
_dealDamage = () =>
{
Debug.Log("Deal damage stub");
};
// тут условно передаем делегат в слой, который отвечает за вызов делегата
PassDealDamageToAnotherLayer();
// подписываемся логикой на делегат
_dealDamage += () =>
{
Debug.Log("Deal damage subscriber");
};
}
private void PassDealDamageToAnotherLayer()
{
// через 5 секунд сделаем вызов делегата
Observable.Timer(TimeSpan.FromSeconds(5)).Subscribe(_ =>
{
_dealDamage();
});
}
}
Подытожу Выбор между реактивным программированием и делегатами в C# зависит от специфики задачи и глубины понимания каждого из подходов.
Реактивное программирование лучше подходит для игр, где важна работа с потоками данных и их обработка в реальном времени.
Делегаты предпочтительнее в ситуациях, где требуется гибкость в реализации обратных вызовов и событий.
Оба подхода имеют свои тонкости и сложности, особенно когда речь идет о multicast делегатах, что требует от разработчика глубокого понимания обоих механизмов для их эффективного использования.
Всем хороших выходных 🖐
Всем привет 👋 Предлагаю принять участие в опросе! На собесах часто спрашивают ➡️ Сколько поколений (количество) использует GC в Unity? Вводные: используем il2cpp backend с выключенным Incremental GC.
Final Results
35%
не использует поколения
7%
1
26%
2
28%
3
4%
Свой вариант ответа
#GC #Unity3D
Приветствую 👋
Подведу итог опроса ➡️ Сколько поколений (количество) использует GC в Unity?
Вводные: используем il2cpp backend с выключенным Incremental GC.
Поясню, что такое поколения:
- Поколения (одно и более) означают, что к частям (фрагментам) кучи применяются критерии возраста.
Даже в алгоритме с одним поколением объекты сортируются по возрасту.
GC выполняет подчистку, в том числе опираясь на эти критерии.
- При отсутствии поколений GC все объекты обрабатываются одинаково, независимо от того, как долго они существовали в памяти.
❗В Unity при использовании il2cpp backend с выключенным Incremental GC используется Boehm-Demers-Weiser (BDW) garbage collector.
Алгоритм работы - Mark-and-Sweep.
Основные этапы работы алгоритма:
- Mark
Сборщик мусора начинает с набора объектов, называемых "корневыми" (Root).
Корневые объекты это те, которые напрямую доступны из стека (например, локальные переменные и параметры функций) или из глобальных переменных.
Сборщик мусора обходит все объекты, доступные из корней, следуя ссылкам между объектами. Каждый достижимый (доступный) объект отмечается как "живой".
Этот процесс продолжается рекурсивно, пока не будут найдены все объекты, доступные из корней.
- Sweep
Сборщик мусора просматривает все объекты в управляемой куче и ищет те, которые не были отмечены на этапе отметки.
Все неотмеченные объекты считаются "мусором" и удаляются, то есть память, которую они занимали, освобождается.
После завершения этапа очистки сборщик мусора снимает отметки с всех оставшихся объектов, чтобы подготовить их к следующему циклу сборки мусора.
Важные моменты в реализации BDW:
- Сканирование Root
- Трассировка объектов. Строит граф объектов и вычисляет их доступность
- Ведет подсчет ссылок на объекты. Требуется для того, чтобы определить, когда на объект больше никто не ссылается
- ❗Не поддерживает поколения
- Выполняет процедуру финализации для недоступных объектов
- Работает в режиме stop the world. Это означает, что выполнение кода приложения периодически полностью приостанавливается.
Поэтому правильным ответом на вопрос будет:
В Unity при использовании il2cpp backend с выключенным Incremental GC поколения не используются!
35% участников ответило правильно 🤝
Всем хорошего дня 👋
Приветствую 👋
Подведу итог опроса ➡️ Сколько поколений (количество) использует GC в Unity?
Вводные: используем il2cpp backend с выключенным Incremental GC.
Поясню, что такое поколения:
- Поколения (одно и более) означают, что к частям (фрагментам) кучи применяются критерии возраста.
Даже в алгоритме с одним поколением объекты сортируются по возрасту.
GC выполняет подчистку, в том числе опираясь на эти критерии.
- При отсутствии поколений GC все объекты обрабатываются одинаково, независимо от того, как долго они существовали в памяти.
❗В Unity при использовании il2cpp backend с выключенным Incremental GC используется Boehm-Demers-Weiser (BDW) garbage collector.
Алгоритм работы - Mark-and-Sweep.
Основные этапы работы алгоритма:
- Mark
Сборщик мусора начинает с набора объектов, называемых "корневыми" (Root).
Корневые объекты это те, которые напрямую доступны из стека (например, локальные переменные и параметры функций) или из глобальных переменных.
Сборщик мусора обходит все объекты, доступные из корней, следуя ссылкам между объектами. Каждый достижимый (доступный) объект отмечается как "живой".
Этот процесс продолжается рекурсивно, пока не будут найдены все объекты, доступные из корней.
- Sweep
Сборщик мусора просматривает все объекты в управляемой куче и ищет те, которые не были отмечены на этапе отметки.
Все неотмеченные объекты считаются "мусором" и удаляются, то есть память, которую они занимали, освобождается.
После завершения этапа очистки сборщик мусора снимает отметки с всех оставшихся объектов, чтобы подготовить их к следующему циклу сборки мусора.
Важные моменты в реализации BDW:
- Сканирование Root
- Трассировка объектов. Строит граф объектов и вычисляет их доступность
- Ведет подсчет ссылок на объекты. Требуется для того, чтобы определить, когда на объект больше никто не ссылается
- ❗Не поддерживает поколения
- Выполняет процедуру финализации для недоступных объектов
- Работает в режиме stop the world. Это означает, что выполнение кода приложения периодически полностью приостанавливается.
Поэтому правильным ответом на вопрос будет:
В Unity при использовании il2cpp backend с выключенным Incremental GC поколения не используются!
35% участников ответило правильно 🤝
Всем хорошего дня 👋