Ответ
Dart использует продвинутый сборщик мусора (Garbage Collector), который сочетает несколько стратегий для минимизации пауз и эффективного управления памятью.
Основные механизмы:
-
Generational Garbage Collection (Поколенческий GC)
- Память разделена на молодое (new space) и старое (old space) поколения.
- Большинство объектов умирают вскоре после создания. GC часто и быстро сканирует молодое поколение, освобождая кратковременные объекты.
- Объекты, пережившие несколько сборок в молодом поколении, продвигаются в старое, которое сканируется реже.
-
Incremental & Concurrent Marking (Инкрементальная и конкурентная маркировка)
- Фаза маркировки (определения живых объектов) выполняется небольшими порциями, чередуясь с выполнением кода приложения, что предотвращает заметные "фризы".
- Маркировка может выполняться параллельно в отдельном потоке (concurrent marking).
-
Compacting (Компактизация)
- После освобождения памяти GC может перемещать оставшиеся объекты, устраняя фрагментацию и ускоряя последующие выделения памяти.
Пример и практические советы:
// Пример циклической ссылки, которая будет корректно обработана современным GC
class Node {
Node? next;
}
void main() {
var a = Node();
var b = Node();
a.next = b;
b.next = a; // Циклическая ссылка
// Современный GC (с подсчётом ссылок или через трёхцветную маркировку) обнаружит,
// что на эту группу объектов нет внешних ссылок, и удалит их.
}
Для оптимизации использования памяти в Flutter-приложениях я следую таким практикам:
- Своевременно отписываюсь: Всегда вызываю
cancel()дляStreamSubscription,Timerи слушателейChangeNotifier/ValueNotifierв методахdispose()виджетов. - Избегаю удержания больших объектов в глобальном контексте без необходимости.
- Использую
const-конструкторы для виджетов и объектов, которые не меняются, чтобы уменьшить нагрузку на GC. - Для кеширования рассматриваю
WeakReferenceиз пакетаdart:weakдля объектов, которые можно безопасно пересоздать, если память понадобится системе.