Как работает сборка мусора в Dart? Какие поколения (generations) ты знаешь?

«Как работает сборка мусора в Dart? Какие поколения (generations) ты знаешь?» — вопрос из категории Dart Core, который задают на 29% собеседований Flutter Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

В Dart используется поколенческий (generational) сборщик мусора (Garbage Collector, GC), оптимизированный для интерактивных приложений с коротким временем жизни большинства объектов, что типично для UI во Flutter.

Основные поколения:

  1. Молодое поколение (Young Generation / Nursery):

    • Сюда попадают все вновь созданные объекты.
    • Сборка мусора здесь происходит часто и быстро (Minor GC). Алгоритм — копирующий (copying).
    • Объекты, пережившие одну сборку, перемещаются в следующее пространство внутри молодого поколения или в старое.
  2. Старое поколение (Old Generation):

    • Здесь находятся долгоживущие объекты, пережившие несколько сборок в молодом поколении.
    • Сборка происходит реже, но может занимать больше времени (Major GC). Используется алгоритм mark-sweep-compact (пометить-очистить-уплотнить).

Как это влияет на разработку во Flutter:

  • Краткосрочные объекты (внутри build()-методов) дешевы. Они создаются в молодом поколении и быстро утилизируются.
  • Избегание утечек памяти: Важно удалять подписки (например, StreamSubscription, Listenable). Несобранные ссылки удерживают объекты в памяти, препятствуя работе GC.
  • Профилирование: В Dart DevTools можно отслеживать пики использования памяти и активность GC.

Пример, создающий нагрузку на GC:

void inefficientBuild() {
  List<String> temporaryList = [];
  for (int i = 0; i < 1000; i++) {
    temporaryList.add('Item $i'); // Создаются тысячи короткоживущих объектов
  }
  // После выхода из метода `temporaryList` и все строки становятся мусором,
  // что провоцирует частые Minor GC.
}

Лучшая практика: Использование const для виджетов и неизменяемых данных, чтобы уменьшить количество создаваемых объектов и нагрузку на GC.