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

Как Dart оптимизирует очистку памяти?

1.2 Junior🔥 151 комментариев
#Dart

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

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

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

Как Dart оптимизирует очистку памяти?

Dart использует продвинутый сборщик мусора (Garbage Collector), специально оптимизированный для мобильных приложений с низкой задержкой и высокой пропускной способностью.

Основные механизмы оптимизации

1. Generational Garbage Collection — поколенческая сборка

Dart разделяет объекты на два поколения для оптимизации сборки:

Young Generation (New Space):
  - Вновь созданные объекты
  - Часто пересматривается
  - Быстрая сборка
  - Размер ~2MB

Old Generation (Old Space):
  - Долгоживущие объекты
  - Редко пересматривается
  - Сборка по необходимости
  - Размер динамический

Это основано на предположении, что молодые объекты умирают быстро, а старые живут долго:

void example() {
  var temp = List.generate(1000, (i) => i);  // New Space
  // ... использование temp ...
}  // temp удаляется при следующей сборке New Space (очень быстро)

class User {
  String name;
  User(this.name);
}

final currentUser = User("Alice");  // Old Space (живёт весь сеанс)

2. Concurrent Marking — параллельная маркировка

Dart выполняет маркировку объектов одновременно с выполнением приложения, минимизируя паузы:

Диаграмма времени сборки:

Before:  [App running] [GC pause] [App running]
         =========    ===        =========
         
With CM: [App + Mark] [Sweep] [App + Mark]
         ============ === ============

3. Incremental Collection — инкрементная сборка

Вместо одной большой паузы, сборка делится на маленькие кусочки:

// Паузы распределяются:
// GC work 1 (1ms) -> App (4ms) -> GC work 2 (1ms) -> App (4ms)
// Вместо одной паузы 8ms

var largeList = List.generate(100000, (i) => i);
// GC работает инкрементально, не блокируя UI

4. Write Barriers — барьеры записи

Optimization для сборки Young Space. Dart отслеживает, когда старый объект ссылается на молодой:

class Parent {
  Child? child;
}

final parent = Parent();  // Old Space
parent.child = Child();   // New Space

// Write barrier запишет эту ссылку в Remember Set
// Это позволит сборщику Old Space знать про ссылку
// без сканирования всего Old Space

Типы сборки мусора

Scavenge GC (New Space)

// Быстрая сборка молодого поколения (обычно < 10ms)
void createTemporaryObjects() {
  for (var i = 0; i < 1000; i++) {
    var temp = List.generate(100, (j) => j);
    // temp автоматически удалится
  }
  // Все 1000 объектов удалены одной Scavenge сборкой
}

Mark-Sweep GC (Old Space)

// Более полная сборка старого поколения
final globalCache = <String, String>{};  // Old Space

void addToCache(String key, String value) {
  globalCache[key] = value;
  // Объекты остаются в памяти
}

// Mark-Sweep сборка происходит редко

Оптимизация через Isolates

Dart использует Isolates для распределения нагрузки:

import 'dart:isolate';

// Главный isolate
void main() async {
  final port = ReceivePort();
  
  // Отдельный isolate для тяжёлых вычислений
  await Isolate.spawn(heavyComputation, port.sendPort);
  
  // Основной isolate не заблокирован
  print('Main isolate remains responsive');
}

void heavyComputation(SendPort sendPort) {
  // Этот isolate имеет собственный heap
  // GC происходит независимо
  var data = List.generate(1000000, (i) => i);
  sendPort.send(data.length);
}

Практические советы оптимизации

1. Избегайте долгоживущих ссылок на временные объекты:

// ❌ Плохо
List<String> cache = [];
void processItems(List<String> items) {
  cache.addAll(items);  // items остаётся в памяти
}

// ✅ Хорошо
void processItems(List<String> items) {
  for (var item in items) {
    processItem(item);  // item автоматически удаляется
  }
}

2. Используйте const для неизменяемых объектов:

// ❌ Плохо
final colors = ['red', 'green', 'blue'];
final colors2 = ['red', 'green', 'blue'];
// Две разные копии в памяти

// ✅ Хорошо
const colors = ['red', 'green', 'blue'];
const colors2 = colors;
// Одна копия, используется везде

3. Деструктуризуйте большие объекты:

class DataHolder {
  late List<int> data;
  late String metadata;
}

final holder = DataHolder();
final justNeeded = holder.metadata;  // Отпустите holder
// holder может быть собран, хотя justNeeded всё ещё в памяти

4. Минимизируйте замыкания:

// ❌ Плохо - замыкание захватывает весь контекст
final heavyList = List.generate(1000000, (i) => i);
final future = Future.delayed(Duration(seconds: 5), () => heavyList.length);
// heavyList не может быть собран 5 секунд

// ✅ Хорошо - захватите только нужное
final heavyList = List.generate(1000000, (i) => i);
final length = heavyList.length;
final future = Future.delayed(Duration(seconds: 5), () => length);
// heavyList может быть собран сразу

Мониторинг GC

import 'dart:developer' as developer;

void monitorMemory() {
  developer.Timeline.startSync('memory-check');
  
  // Ваш код
  var data = List.generate(100000, (i) => i);
  
  developer.Timeline.finishSync();
  
  // Информация записывается в Dart DevTools
}

Результаты оптимизации

  • GC паузы < 10ms для молодого поколения
  • 60 FPS возможна благодаря инкрементной сборке
  • Минимальный overhead для переживающих сборки объектов
  • Масштабируемость от встроенных до рабочих станций

Optimizованный GC Dart — это причина, почему Flutter приложения способны поддерживать высокую частоту кадров на дешёвых мобильных устройствах.

Как Dart оптимизирует очистку памяти? | PrepBro