Что такое утечка памяти и как она возникает?
Sobes Copilot
Получайте ответы в реальном времени
Ответ от нейросети
sobes.tech AI
Утечка памяти (memory leak) — это ситуация, когда выделенная память больше не используется программой, но остается недоступной для сборщика мусора (или системы управления памятью), поскольку на нее продолжают ссылаться объекты. В iOS это происходит из-за циклических ссылок между объектами, которые используют Automatic Reference Counting (ARC).
Как возникает:
ARC в iOS автоматически управляет памятью, освобождая объекты, когда на них нет активных ссылок. Утечка возникает, когда два или более объекта ссылаются друг на друга сильными (по умолчанию) ссылками, создавая замкнутый цикл. В этом случае счетчик ссылок каждого объекта никогда не достигает нуля, даже если на эту группу объектов нет внешних ссылок. ARC не может освободить эти объекты.
Пример:
class Parent {
var child: Child?
// ...
deinit {
print("Parent deinitialized")
}
}
class Child {
var parent: Parent?
// ...
deinit {
print("Child deinitialized")
}
}
func createLeak() {
let parent = Parent()
let child = Child()
parent.child = child
child.parent = parent // Сильная циклическая ссылка
}
createLeak()
// parent и child будут существовать после выхода из функции,
// несмотря на то, что на них нет внешних ссылок
// Сообщения deinit не будут напечатаны
В данном примере parent сильно ссылается на child, а child сильно ссылается на parent. Это создает цикл. Когда функция createLeak завершается, локальные переменные parent и child выходят из области видимости, но сильные ссылки между экземплярами Parent и Child остаются, предотвращая их освобождение ARC.
Для предотвращения утечек памяти в iOS используются слабые (weak) и бесхозные (unowned) ссылки, которые не увеличивают счетчик ссылок объекта.
weak: Используется, когда срок жизни объектов может быть разным. Слабая ссылка может статьnil, если объект, на который она ссылается, будет освобожден.unowned: Используется, когда срок жизни ссылающегося объекта не превышает срока жизни объекта, на который указывает бесхозная ссылка. Бесхозная ссылка всегда имеет значение и не может бытьnil. Обращение к освобожденному объекту поunownedссылке приведет к ошибке времени выполнения.
class Parent {
var child: Child?
// ...
deinit {
print("Parent deinitialized")
}
}
class Child {
weak var parent: Parent? // Используем слабую ссылку
// ...
deinit {
print("Child deinitialized")
}
}
func fixLeak() {
let parent = Parent()
let child = Child()
parent.child = child
child.parent = parent // Теперь связка родитель-потомок не содержит циклической сильной связи
}
fixLeak()
// parent и child будут освобождены после выхода из функции,
// поскольку циклическая сильная ссылка устранена
// Сообщения deinit будут напечатаны