Ответ
В Dart Garbage Collector (GC) — это механизм автоматического управления памятью, который освобождает память, занятую объектами, ставшими недостижимыми. Dart использует generational garbage collection с двумя основными поколениями:
- Молодое поколение (Young Generation): Использует быстрый алгоритм scavenger для очистки короткоживущих объектов (например, временных переменных в методе
build). Сборка мусора здесь происходит часто и быстро. - Старое поколение (Old Generation): Для долгоживущих объектов используется более медленный алгоритм (mark-sweep или mark-compact).
Практическое влияние на Flutter:
- Микрофризы (jank): Длительная сборка мусора в основном потоке может вызвать пропуск кадров. Это критично для анимаций и скроллинга.
- Оптимизации:
- Избегайте создания лишних объектов в часто вызываемых методах (
build,didUpdateWidget, анимационных листенерах). Используйтеconstконструкторы для виджетов. - Для отложенной инициализации тяжёлых объектов используйте
late final. - Управляйте подписками (
StreamSubscription,Listenable) и явно отменяйте их вdispose, чтобы объекты стали недостижимыми раньше.
- Избегайте создания лишних объектов в часто вызываемых методах (
Пример плохой и хорошей практики:
// Плохо: Создаёт новый список на каждом вызове build
Widget build(BuildContext context) {
List<Widget> items = []; // Новый объект каждый кадр
for (var i = 0; i < 100; i++) {
items.add(Text('Item $i'));
}
return ListView(children: items);
}
// Лучше: Кэширование списка (если данные статичны)
class MyWidget extends StatelessWidget {
final List<Widget> _cachedItems = List.generate(
100,
(i) => Text('Item $i'),
);
@override
Widget build(BuildContext context) {
return ListView(children: _cachedItems);
}
} Ответ 18+ 🔞
Ага, слушай, про сборщик мусора в Dart. Ну, это такая штука, которая сама за тобой убирает, как мама в детстве, когда ты игрушки по всей комнате разбросал и забыл. Только тут не игрушки, а объекты в памяти, которые уже никому не нужны.
Вот смотри, как оно работает, ёпта. У них там система, прямо как в армии: есть молодое поколение и старое поколение.
- Молодое поколение — это как новобранцы-срочники. Живут недолго, создал переменную в методе
build— и через милисекунду её уже нет. Уборка там быстрая, частенько происходит, по принципу «собрал-выкинул». Никакой мороки. - А вот старое поколение — это уже старослужащие, офицеры. Тут всё серьёзнее. Объекты живут долго, и чтобы их убрать, нужно провести полноценную инвентаризацию: пометить всех, кто ещё нужен, а потом вычистить тех, кто не нужен. Процесс, понятное дело, подольше.
А теперь самое важное, на что это влияет в Flutter:
Представь, у тебя плавная анимация идёт, или ты листаешь ленту, а тут БАЦ — и сборщик мусора в старом поколении решил поработать. Он может на пару кадров всё подвесить! Это и есть тот самый jank, микрофриз, от которого у пользователей волосы дыбом встают. Терпения ноль ебать у людей, если приложение дёргается.
Так что же делать, чтобы не было пиздеца?
Главная мысль — не создавай овердохуища мусора там, где это не нужно. Особенно в тех методах, которые вызываются 60 раз в секунду.
- Избегай как огня создания кучы новых объектов в
build, в анимационных коллбеках или вdidUpdateWidget. Зачем каждый раз новый список городить, если можно один создать и переиспользовать? - Вот смотри, классический косяк и как его исправить:
// Пиздопроебищный код. Каждый раз, когда экран перерисовывается,
// ты создаёшь новый список. Сборщик потом с ума сойдёт, убирая эту кучу.
Widget build(BuildContext context) {
List<Widget> items = []; // Новый объект каждый кадр, ядрёна вошь!
for (var i = 0; i < 100; i++) {
items.add(Text('Item $i'));
}
return ListView(children: items);
}
// А вот уже умный подход. Создали список один раз и кэшировали.
// Теперь в `build` мы его просто возвращаем, не порождая новый мусор.
// GC доволен, фпс стабильный, все живы.
class MyWidget extends StatelessWidget {
final List<Widget> _cachedItems = List.generate(
100,
(i) => Text('Item $i'),
);
@override
Widget build(BuildContext context) {
return ListView(children: _cachedItems);
}
}
Ещё лайфхак: для тяжёлых объектов, которые инициализируются один раз, юзай late final. И подписки всякие на стримы или анимации — обязательно отменяй в dispose(). А то останутся они висеть в памяти, как призраки, и сборщик будет на них коситься, но тронуть не посмеет. Доверия ебать ноль у него к таким недобитым ссылкам.
Короче, суть в том, чтобы думать головой. Не плоди сущности без нужды, и тогда GC не будет тебе палки в колёса в самый ответственный момент вставлять. Всё просто, как три копейки.
Видео-ответы
▶
▶
▶
▶
▶
▶
▶
▶