← Назад к вопросам

С какой областью памяти работает Garbage Collector?

2.0 Middle🔥 111 комментариев
#Dart

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Garbage Collector и области памяти в Dart/Flutter

Основы памяти в Dart

Dart использует управляемое выделение памяти с автоматической очисткой. Память делится на несколько областей:

Heap (куча) — главная зона ответственности GC

Это основная область, где Garbage Collector работает:

  • Все объекты (классы, листы, маппы, строки)
  • Все динамические структуры данных
  • Все экземпляры, созданные с new

Пример:

var person = Person(name: "John");  // выделяется в Heap
var items = [1, 2, 3];               // List в Heap
var data = {"key": "value"};        // Map в Heap

GC отслеживает объекты в Heap и удаляет те, на которые нет ссылок.

Stack (стек) — автоматическая очистка

  • Локальные переменные примитивных типов
  • Ссылки на объекты в Heap
  • Параметры функций
  • Возвращаемые значения

Пример:

void myFunction() {
  int x = 5;           // Stack — примитив
  var obj = MyClass(); // Stack получает ссылку, сам объект в Heap
}
// После выхода из функции локальные переменные автоматически удаляются

Stack очищается автоматически при выходе из области видимости — GC здесь не нужен.

Как работает Garbage Collector в Dart

Generational GC:

  • Young Generation — новые объекты (быстрая сборка)
  • Old Generation — долгоживущие объекты (редкая сборка)

Этот подход основан на гипотезе поколений: новые объекты чаще становятся мусором.

Mark-and-Sweep алгоритм:

  1. Mark фаза — отмечаются живые объекты (из Stack и из других живых объектов)
  2. Sweep фаза — удаляются неотмеченные объекты

Практический пример утечки памяти

class MyWidget extends StatefulWidget {
  @override
  State<MyWidget> createState() => _MyWidgetState();
}

class _MyWidgetState extends State<MyWidget> {
  late StreamSubscription subscription;
  
  @override
  void initState() {
    super.initState();
    // ПРОБЛЕМА: подписка держит ссылку на State
    subscription = streamController.stream.listen((data) {
      // обработка
    });
  }
  
  @override
  void dispose() {
    // РЕШЕНИЕ: отписываемся явно перед удалением Widget
    subscription.cancel();
    super.dispose();
  }
}

Без subscription.cancel() GC не сможет удалить Widget, даже если он больше не видим на экране.

Производительность и оптимизация

Избежание частой аллокации:

// Плохо — создаёт новый список каждый фрейм
Widget build(BuildContext context) {
  return Column(children: <Widget>[...].toList()); // новый List
}

// Хорошо — переиспользуем список
final List<Widget> _children = [...];
Widget build(BuildContext context) {
  return Column(children: _children);
}

Явное управление ресурсами:

// Закрытие потоков, контроллеров, соединений
@override
void dispose() {
  _controller.dispose();  // освобождаем контроллер
  _streamSubscription.cancel();
  super.dispose();
}

Ключевые выводы

  • GC работает с Heap, где хранятся все объекты
  • Stack автоматический, не требует GC
  • Памятью нужно управлять явно — закрывать потоки, подписки, контроллеры
  • Generational approach — новые объекты проверяются чаще
  • Утечки в Flutter часто из-за незакрытых ресурсов, а не из-за GC
С какой областью памяти работает Garbage Collector? | PrepBro