Что такое Garbage Collector и как управление памятью работает в Swift?

Ответ

Garbage Collector (GC) — алгоритм автоматического управления памятью, который периодически находит и удаляет неиспользуемые объекты. В Swift/Objective-C для iOS/macOS GC не используется — вместо него применяется ARC (Automatic Reference Counting).

ARC vs Garbage Collector:

Критерий ARC (Swift/Objective-C) Garbage Collector (Java/C#)
Принцип работы Подсчёт ссылок во время компиляции/выполнения Периодическое сканирование «живых» объектов
Время освобождения Немедленно при достижении счётчиком нуля Неопределённое (при срабатывании GC)
Производительность Предсказуемая, без пауз Возможны stop-the-world паузы
Циклические ссылки Требуют weak/unowned Автоматически обнаруживаются

Пример ARC в Swift:

class User {
    let name: String
    var friend: User? // Сильная ссылка → возможен retain cycle

    init(name: String) { self.name = name }
    deinit { print("(name) удалён из памяти") }
}

// Создаём циклическую ссылку
var alice: User? = User(name: "Alice")
var bob: User? = User(name: "Bob")
alice?.friend = bob  // Alice → Bob
bob?.friend = alice  // Bob → Alice (цикл!)

alice = nil  // Память НЕ освобождается!
bob = nil    // Оба объекта всё ещё в памяти

Решение с weak reference:

class User {
    let name: String
    weak var friend: User? // ← Слабая ссылка разрывает цикл

    init(name: String) { self.name = name }
}

// Теперь при alice = nil и bob = nil память корректно освобождается

Ключевые механизмы Swift:

  • Strong — обычная ссылка (увеличивает счётчик)
  • Weak — не удерживает объект (автоматически становится nil)
  • Unowned — как weak, но предполагает, что объект существует (краш при обращении к освобождённому)
  • Autorelease pools — для Objective-C совместимости, отложенное освобождение

Ответ 18+ 🔞

А, ну вот, опять про эту вашу память, блядь. Сидишь такой, пишешь код, а тут — бац! — и вылезло. Слушай, давай по-простому, без этих ваших академических закидонов.

Вот смотри, в джаве там или шарпе — там, блядь, мусорщик. Сидит такой уборщик, ленивая жопа, и ждёт, пока куча говна не накопится. А потом раз — и stop-the-world, вся вселенная замирает, пока он метлой там машет, выгребая твои недоделанные объекты. Производительность, сука, скачет, как хуй в проруби. Паузы, неопределёнённость — пиздец, а не жизнь.

А у нас в свифте — другое дело, блядь. Тут ARC. Это не мусорщик, это, блядь, бухгалтер скрупулёзный. Каждый объект — как начальник цеха. Завёл нового работника (создал объект) — бухгалтер ставит ему единичку в графу «сильные ссылки». Передал его в другой отдел (присвоил переменной) — бухгалтер карандашиком: «плюс один». Уволился работник (переменная занулилась) — «минус один». Как только счётчик в ноль — тут же, без разговоров, вышвыривают этого работника в окно, память освобождают. Мгновенно, блядь, без пауз. Предсказуемо, как удар в ебло.

Но, как всегда, есть нюанс, ёпта. Циклические ссылки. Вот смотри, какой пиздец может случиться:

class Человек {
    let имя: String
    var друг: Человек? // Сильная ссылка, блядь!

    init(имя: String) { self.имя = имя }
    deinit { print("(имя) — откинулся, память свободна") }
}

// Создаём двух долбоёбов
var вася: Человек? = Человек(имя: "Вася")
var петя: Человек? = Человек(имя: "Петя")

// И они начинают дружить. Крепко.
вася?.друг = петя  // Вася крепко держит Петю
петя?.друг = вася  // Петя крепко держит Васю. Ёбушки-воробушки, замкнутый круг, блядь!

вася = nil  // Думаешь, Вася свободен? Хуй там!
петя = nil  // И Петя тоже! Они оба, как два мудака в обнимку, болтаются в памяти навечно!
// deinit не вызовется ни у кого! Утечка памяти, пиздец полный.

Вот видишь? Они друг за друга держатся, счётчики ссылок у них по единице, и бухгалтер (ARC) такой: «Ну раз на них ещё кто-то ссылается, пусть живут». А ссылаются-то они ДРУГ НА ДРУГА, блядь! Классический пиздец.

И что делать? А надо одного из них ослабить хватку, сделать слабаком. Для этого есть weak:

class УмныйЧеловек {
    let имя: String
    weak var друг: УмныйЧеловек? // ← Слабая ссылка! Не увеличивает счётчик!

    init(имя: String) { self.имя = имя }
}

// Теперь, когда мы занулим переменные, они оба благополучно сдохнут, как и положено.
// Потому что Петя держит Васю слабо, не по-мужски. И как только внешняя ссылка пропала — всё, пиzдец.

Ещё есть unowned — это как weak, но для отчаянных. Предполагается, что объект, на который ссылаешься, переживёт тебя. Если ошибёшься — получишь краш, блядь, в лучших традициях. Как прыжок с крыши, рассчитывая, что внизу батут, а там асфальт.

Итог, коротко:

  • Сильные (strong) — обычные, держат крепко. Основные.
  • Слабые (weak) — для разрыва циклов. Автоматически становятся nil.
  • Бессобственные (unowned) — для разрыва циклов, когда уверен, что объект жив. Если не уверен — летишь в тартарары, краш.
  • Autorelease pools — это уже для совместимости со старым добрым Objective-C, чтоб не засирать память сразу, а чуть позже. Но это уже другая история, блядь.

Вот и вся магия. ARC — это чётко, быстро, но требует, чтобы ты, блядь, головой думал, кто на кого и как ссылается. А то получишь утечку, и приложение твоё сожрёт всю оперативку, как мартышлюшка бананы.