Сегодня поговорим об утечках памяти во Flutter-приложениях. Рассмотрим, что может их вызывать и почему не все объекты очищаются самостоятельно.
В самом простом понимании утечка памяти — это ситуация, когда программа хранит в памяти объект, который уже не нужен. На первый взгляд она может показаться достаточно безобидной, но на самом деле способна привести к серьезным проблемам — медленной работе приложения, сбоям и даже крэшам.
Для снижения утечек памяти в Dart есть специальный механизм —Garbage Collector (GC). Его основная задача — выполнять автоматическую очистку неиспользуемых объектов в программе. GC самостоятельно отслеживает все объекты, которые создаются в процессе работы. Затем очищает те объекты, которые не имеют активные ссылки в программе.
Представим, что у нас есть некоторый класс
User. Метод createUser() внутри себя создаст его экземпляр и выполнит с ним некоторые манипуляции. После завершения работы метода createUser() объект user больше не будет иметь активных ссылок, и GC легко его очистит. void main() {
createUser(); // Вызываем функцию, которая внутри создает пользователя
print('Пользователь создан, но больше не используется');
// После этого GC может удалить объект User
}
void createUser() {
final user = User(name: 'Anna');
print('Привет, ${user.name}');
// Когда функция завершится, переменная user исчезнет из области видимости
}
Но если создать пользователя на уровень выше, в самом
main(), GC очистить его не сможет, так как активная ссылка будет существовать. void main() {
final user = User('Alice');
// Даже если мы больше не используем user, ссылка на него все еще существует.
// GC не удалит объект.
}
Больше подробностей о работе GC можете найти в этих статьях
▪️ Flutter: Don’t Fear the Garbage Collector
▪️ Garbage Collection in Dart and Its Implications in Flutter
▪️ How Dart’s Garbage Collector Works (And When It Fails You!)
Как мы выяснили, Garbage Collector не может очистить все объекты, поэтому многие источники утечки памяти разработчику требуется отслеживать самостоятельно.
Наиболее часто встречающиеся:
✔️ контроллеры — например, TextEditingController, PageController
✔️ подписки — StreamSubscription
✔️ таймеры — Timer
✔️ слушатели — при добавлении addListener()
✔️ глобальные и статические объекты
Здесь стоит соблюдать ряд простых правил:
▫️ если создаете контроллер или подписку, обязательно вызывайте методы
dispose() или cancel()▫️ таймеры также необходимо отменять с помощью
cancel()▫️ при добавлении слушателя через
addListener() не забывайте удалять его через removeListener()▫️ если в коде глобальные или статические объекты вам больше не нужны, можно явно обнулить их ссылки, присвоив
null▫️ систематически проверяйте свое приложение на утечки памяти
📎Отследить утечки памяти вам помогут специальные инструменты, например, Dart DevTools (вкладка Memory) и библиотека leak_tracker_flutter_testing.
