Что такое утечки памяти?
Sobes Copilot
Получайте ответы в реальном времени
Ответ от нейросети
sobes.tech AI
Утечка памяти в iOS — это ситуация, когда память, выделенная для объекта, больше не используется приложением, но система не может ее освободить, так как на этот объект до сих пор существуют сильные ссылки. Со временем это приводит к исчерпанию доступной памяти и, как следствие, к замедлению работы приложения или его аварийному завершению.
Основные причины утечек памяти связаны с циклами сильных ссылок (Strong Reference Cycles), когда два или более объекта сильно ссылаются друг на друга, предотвращая их освобождение, даже если к ним больше нет доступа извне.
Для предотвращения утечек памяти используются:
-
Automatic Reference Counting (ARC): Автоматическое управление памятью в Swift и Objective-C, которое отслеживает и управляет временем жизни объектов, автоматически освобождая память, когда strong reference count объекта становится равным нулю.
-
weak и unowned ключевые слова:
weakиспользуется для ссылок, которые не должны препятствовать освобождению объекта, на который они ссылаются. Ссылка становитсяnil, когда объект освобождается. Используется для предотвращения циклов сильных ссылок между объектами, где один объект может существовать без другого, или когда связь является опциональной.unownedтакже не удерживает сильной ссылки на объект, но в отличие отweak, предполагается, что ссылающийся объект будет иметь такое же или более короткое время жизни, чем объект, на который ссылаются.unownedссылка не опциональна и не становитсяnil. Если объект, на который ссылаются, освобождается до того, какunownedссылка будет использована, это приведет к крашу.
Примеры использования weak и unowned в циклах замыканий:
// Пример цикла сильных ссылок с замыканием
class Person {
let name: String
var apartment: Apartment?
init(name: String) {
self.name = name
print("\(name) is being initialized")
}
deinit {
print("\(name) is being deinitialized")
}
}
class Apartment {
let unit: String
var tenant: Person?
init(unit: String) {
self.unit = unit
print("Apartment \(unit) is being initialized")
}
deinit {
print("Apartment \(unit) is being deinitialized")
}
}
var john: Person? = Person(name: "John Appleseed")
var unit4A: Apartment? = Apartment(unit: "4A")
john!.apartment = unit4A
unit4A!.tenant = john
john = nil // deinit не вызван
unit4A = nil // deinit не вызван
// Произошла утечка памяти из-за цикла сильных ссылок
// Решение с использованием weak или unowned
class PersonFixed {
let name: String
var apartment: ApartmentFixed?
init(name: String) {
self.name = name
print("\(name) is being initialized")
}
deinit {
print("\(name) is being deinitialized")
}
}
class ApartmentFixed {
let unit: String
weak var tenant: PersonFixed? // Использование weak для разрыва цикла
init(unit: String) {
self.unit = unit
print("Apartment \(unit) is being initialized")
}
deinit {
print("Apartment \(unit) is being deinitialized")
}
}
var johnFixed: PersonFixed? = PersonFixed(name: "John Appleseed")
var unit4AFixed: ApartmentFixed? = ApartmentFixed(unit: "4A")
johnFixed!.apartment = unit4AFixed
unit4AFixed!.tenant = johnFixed
johnFixed = nil // deinit для PersonFixed вызван
unit4AFixed = nil // deinit для ApartmentFixed вызван
// Память освобождена
В замыканиях cycle reference решается использованием capture list:
class HTMLElement {
let name: String
let text: String?
lazy var asHTML: () -> String = {
[unowned self] in // Использование unowned в capture list
if let text = self.text {
return "<\(self.name)> \(text) </\(self.name)>"
} else {
return "<\(self.name)>"
}
}
init(name: String, text: String? = nil) {
self.name = name
self.text = text
}
deinit {
print("\(name) is being deinitialized")
}
}
var paragraph: HTMLElement? = HTMLElement(name: "p", text: "hello, world")
print(paragraph!.asHTML())
paragraph = nil // deinit вызван
Инструменты для выявления утечек памяти включают:
- Instruments (Leaks): Мощный инструмент в Xcode Profile, который отслеживает выделенную и освобожденную память, показывая объекты, которые должны были быть освобождены, но не были.
- Memory Graph Debugger: Встроенный в Xcode отладчик графа памяти, позволяющий визуализировать взаимосвязи между объектами и находить циклы сильных ссылок.
- Static Analyzer: В Xcode анализирует код и может предупредить о потенциальных утечках памяти и других логических ошибках.