# Сборка мусора vs ручное управление памятью

> Сравнение способов освобождения памяти в языках программирования — ручное (C), RAII и умные указатели (C++), подсчёт ссылок (Python, Swift), трассирующая сборка мусора (Go, Java) и владение (Rust).

Источник: https://llmdocs.ru/wiki/gc-vs-manual-memory/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0

- **Ручное управление**: C (malloc/free)
- **RAII и умные указатели**: C++, Rust
- **Подсчёт ссылок**: CPython, Swift (ARC), Rust (Rc, Arc)
- **Трассирующая сборка мусора**: Go, Java, C#, JavaScript
- **Владение и заимствование**: Rust (проверка при компиляции)
- **Первая сборка мусора**: Lisp, Джон Маккарти (1959–1960)
- **Цена ошибок**: около 70% уязвимостей в крупных кодовых базах на C и C++ связаны с памятью
**Управление памятью** — способ, которым программа получает память для данных и возвращает её, когда данные больше не нужны. Языки решают эту задачу по-разному: в C программист освобождает память вручную, в [Go](https://llmdocs.ru/wiki/go.md), Java и [Python](https://llmdocs.ru/wiki/python.md) этим занимается **сборщик мусора**, а [Rust](https://llmdocs.ru/wiki/rust.md) проверяет правила владения при компиляции и освобождает память автоматически без сборщика. Выбор подхода определяет безопасность, производительность, предсказуемость задержек и удобство языка.

## Проблема

Данные с неизвестным заранее временем жизни размещаются в **куче**. Их нужно освободить ровно один раз и ровно тогда, когда никто больше ими не пользуется. Ошибки приводят к тяжёлым последствиям:

| Ошибка | Что происходит |
|---|---|
| Утечка памяти | память не освобождается, процесс постепенно разрастается |
| Использование после освобождения (*use-after-free*) | чтение или запись в чужие данные, уязвимости |
| Двойное освобождение | повреждение структур аллокатора |
| Выход за границы буфера | перезапись соседних данных, классический способ взлома |

По данным Microsoft и проекта Chromium, около 70% серьёзных уязвимостей в их кодовых базах на C и C++ связаны именно с безопасностью памяти.[4][5] Поэтому государственные агентства и крупные компании рекомендуют переходить на языки с безопасной памятью.

## Подходы

### Ручное управление

В C память выделяют `malloc` и освобождают `free`. Это даёт полный контроль и предсказуемость, но вся ответственность лежит на программисте, и ошибки из таблицы выше неизбежны в больших программах. Инструменты — AddressSanitizer, Valgrind — помогают находить их при тестировании.

### RAII и умные указатели

В C++ ресурс привязывается к времени жизни объекта (*Resource Acquisition Is Initialization*): деструктор освобождает память, закрывает файл или снимает блокировку при выходе из области видимости. Умные указатели `unique_ptr` (единственный владелец) и `shared_ptr` (подсчёт ссылок) избавляют от большинства ручных `delete`, но язык не запрещает небезопасные приёмы.

### Подсчёт ссылок

У каждого объекта есть счётчик ссылок; когда он падает до нуля, объект немедленно освобождается. Так работает [CPython](https://llmdocs.ru/wiki/cpython.md), Swift (автоматический подсчёт ссылок, ARC) и типы `Rc`/`Arc` в Rust. Плюсы — предсказуемое освобождение без пауз. Минусы — накладные расходы на каждое присваивание и **циклические ссылки**: два объекта, ссылающиеся друг на друга, никогда не освободятся. CPython дополняет подсчёт ссылок циклическим сборщиком мусора.[3]

### Трассирующая сборка мусора

Идею автоматической сборки мусора предложил Джон Маккарти для языка Lisp в 1959–1960 годах.[1] Сборщик периодически находит все объекты, достижимые от «корней» — глобальных переменных и стека, — а остальные считает мусором. Варианты:[6]

- **Пометка и очистка** (*mark-sweep*) — пометить достижимое, освободить остальное.
- **Поколенческая** сборка — большинство объектов умирает молодыми, поэтому молодое поколение проверяется часто, старое — редко (Java, .NET, V8).
- **Конкурентная** сборка — основная работа выполняется параллельно с программой, паузы сокращаются до долей миллисекунды. Сборщик Go — конкурентный трёхцветный mark-sweep, настраиваемый параметрами `GOGC` и `GOMEMLIMIT`.[2]

Плюсы — простота для программиста и безопасность: невозможно обратиться к освобождённой памяти. Минусы — дополнительная память (сборщику нужен запас), паузы и затраты процессора, менее предсказуемые задержки. Для большинства серверных приложений это приемлемо; для систем жёсткого реального времени, ядер ОС и игровых движков — часто нет.

### Владение и заимствование

Rust применяет правила [владения](https://llmdocs.ru/wiki/ownership-borrowing.md) на этапе компиляции: у каждого значения один владелец, при выходе владельца из области видимости память освобождается (как RAII), а ссылки-заимствования не могут пережить данные, на которые указывают. Ошибки использования после освобождения и гонки данных отсекаются компилятором, а во время выполнения нет ни сборщика, ни накладных расходов. Цена — более сложное обучение и необходимость выражать структуры с общими ссылками через `Rc`, `Arc` и индексы.

## Сравнение

| | Ручное (C) | RAII (C++) | Подсчёт ссылок | Трассирующий GC (Go, Java) | Владение (Rust) |
|---|---|---|---|---|---|
| Безопасность памяти | нет | частичная | да | да | да (вне `unsafe`) |
| Паузы | нет | нет | нет (кроме сборки циклов) | короткие, но есть | нет |
| Накладные расходы | минимальные | минимальные | на каждое присваивание | память и процессор сборщика | минимальные |
| Сложность для программиста | высокая | средняя | низкая | низкая | средняя или высокая |
| Утечки | возможны | возможны | при циклах | редки | возможны, но редки |

## Как выбирать

- Сетевые сервисы, инструменты, бизнес-логика — языки со сборкой мусора (Go, Java, C#, Python) дают высокую продуктивность при достаточной скорости.
- Системное программирование, встраиваемые системы, низкие и предсказуемые задержки, библиотеки для других языков — Rust, а в существующих кодовых базах — C и C++.
- Утечки возможны в любом языке: кэш без ограничения размера или забытые подписки удерживают объекты и под сборщиком мусора.

## См. также

- [Владение и заимствование (Rust)](https://llmdocs.ru/wiki/ownership-borrowing.md)
- [Go vs Rust — сравнение](https://llmdocs.ru/wiki/go-vs-rust.md)
- [Сборка мусора](https://llmdocs.ru/wiki/garbage-collection.md)
- [CPython](https://llmdocs.ru/wiki/cpython.md)
- [Unsafe Rust](https://llmdocs.ru/wiki/unsafe-rust.md)

## Источники

1. [J. McCarthy — Recursive Functions of Symbolic Expressions and Their Computation by Machine (CACM, 1960)](https://dl.acm.org/doi/10.1145/367177.367199)
2. [A Guide to the Go Garbage Collector](https://go.dev/doc/gc-guide)
3. [Python — gc: Garbage Collector interface](https://docs.python.org/3/library/gc.html)
4. [Microsoft Security Response Center — A proactive approach to more secure code (2019)](https://msrc.microsoft.com/blog/2019/07/a-proactive-approach-to-more-secure-code/)
5. [The Chromium Projects — Memory safety](https://www.chromium.org/Home/chromium-security/memory-safety/)
6. [R. Jones, A. Hosking, E. Moss — The Garbage Collection Handbook](https://gchandbook.org/)
