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

Как устроена память в Dart?

2.8 Senior🔥 111 комментариев
#Dart#Архитектура Flutter

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

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

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

Как устроена память в Dart

Память в Dart управляется автоматически через сборщик мусора (GC). Понимание её структуры критично для оптимизации производительности приложений Flutter.

Структура памяти

Память в Dart разделяется на несколько областей:

1. Heap (кучи)

Heap — основная область для хранения объектов:

  • Young Generation — для новых объектов
  • Old Generation — для долгоживущих объектов
  • Large Object Space — для больших объектов (строки, списки)

2. Stack (стек)

Stack хранит:

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

Жизненный цикл объекта

1. Создание → объект в Young Generation
   ↓
2. Молодой GC → выживают → перемещаются в Old Generation
   ↓
3. Full GC → удаляются неиспользуемые

Сборка мусора (Garbage Collection)

Mark-Sweep-Compact алгоритм

1. Mark (Пометка) — рекурсивно пометить живые объекты
   ↓
2. Sweep (Метание) — удалить неживые объекты
   ↓
3. Compact (Уплотнение) — переместить живые объекты в начало

Generational GC

Dart использует поколенческую сборку мусора:

// Молодое поколение (часто собирается)
var temp = [];
for (int i = 0; i < 1000; i++) {
  temp.add(i); // Быстро удаляется после цикла
}

// Старое поколение (редко собирается)
static final cache = <String, String>{};

Примеры управления памятью

Проблема: Утечка памяти

// ❌ Плохо — утечка памяти
class MyWidget extends StatefulWidget {
  @override
  State<MyWidget> createState() => _MyWidgetState();
}

class _MyWidgetState extends State<MyWidget> {
  Timer? _timer;

  @override
  void initState() {
    super.initState();
    // Timer удерживает ссылку на этот widget
    _timer = Timer.periodic(Duration(seconds: 1), (_) {
      if (mounted) {
        setState(() {});
      }
    });
  }

  @override
  void dispose() {
    // ❌ Забыли отменить таймер!
    // _timer?.cancel();
    super.dispose();
  }
}

Решение: Правильная очистка

// ✅ Хорошо — нет утечки
@override
void dispose() {
  _timer?.cancel();
  _subscription?.cancel();
  _controller?.dispose();
  super.dispose();
}

Типы данных в памяти

Примитивные типы в Stack

void example() {
  int age = 25;      // Stack
  bool isActive = true; // Stack
  double price = 99.99;  // Stack
}

Объекты в Heap

void example() {
  String name = "Flutter"; // Объект в Heap, ссылка в Stack
  List<int> numbers = [1, 2, 3]; // Объект в Heap
  Map<String, int> data = {}; // Объект в Heap
}

Оптимизация памяти

1. Переиспользование объектов

// ❌ Создание новых объектов каждый раз
class Painter {
  void paint(Canvas canvas) {
    final paint = Paint() // Новый объект каждый фрейм!
      ..color = Colors.blue
      ..strokeWidth = 2;
    canvas.drawLine(Offset(0, 0), Offset(100, 100), paint);
  }
}

// ✅ Переиспользование
class Painter {
  late final Paint _paint = Paint()
    ..color = Colors.blue
    ..strokeWidth = 2;
    
  void paint(Canvas canvas) {
    canvas.drawLine(Offset(0, 0), Offset(100, 100), _paint);
  }
}

2. Избегание больших временных объектов

// ❌ Плохо — создание большого списка
List<int> getNumbers() {
  return List.generate(1000000, (i) => i);
}

// ✅ Хорошо — использование итератора
Iterable<int> getNumbers() {
  return Iterable.generate(1000000, (i) => i);
}

3. Очистка ресурсов

class DataFetcher {
  StreamSubscription? _subscription;
  AnimationController? _controller;
  
  void start() {
    _subscription = stream.listen((_) {});
    _controller = AnimationController(vsync: this);
  }
  
  void stop() {
    _subscription?.cancel();
    _controller?.dispose();
  }
}

Инструменты анализа памяти

DevTools Memory Tab

flutter run --profile
# Откроется DevTools, перейди на Memory вкладку

Dart VM Service

// Проверить размер объектов
print("String size: ${"hello".toString()}");

Важные правила

  • Dispose всегда — AnimationController, StreamSubscription, Timer
  • Избегай циклических ссылок — объекты не смогут быть собраны
  • Используй const для неизменяемых значений
  • Ленивая инициализация — создавай объекты только когда нужны
  • Профилируй — используй DevTools перед оптимизацией

Память — это то, что часто упускают новички. Правильное её управление делает приложение быстрым, стабильным и приятным для использования.