Компиляторы
Управление памятью вручную
70% всех CVE в Chrome, Android и Windows связаны с ошибками управления памятью: use-after-free, buffer overflow, double-free. Не потому что разработчики неопытные - а потому что C/C++ не дают инструментов для статической проверки. Rust borrow checker делает эти классы ошибок невозможными на этапе компиляции. Это объясняет, почему Microsoft, Google и Android переписывают системный код на Rust.
- **jemalloc** в Rust std и Firefox: снижение фрагментации heap на 20-40% по сравнению с glibc malloc, особенно заметно в долгоживущих процессах
- **LLVM BumpPtrAllocator**: Clang аллоцирует ~90% AST nodes через bump allocator - это одна из причин быстрого времени компиляции Clang по сравнению с GCC
- **Android 13+**: ~1.5M строк Rust в AOSP, включая Bluetooth stack и Keystore2 - с 2021 года zero CVE по memory safety в Rust-компонентах
malloc/free и аллокаторы
malloc (memory allocator) управляет heap через списки свободных блоков. glibc malloc (ptmalloc2) использует bins: small bins для блоков 16-504B, large bins для больших, unsorted bin как буфер. При free() блок возвращается в bin и по возможности сливается с соседними. Каждый блок имеет 8-16 байт metadata overhead.
Heap fragmentation - практическая проблема: после миллионов аллокаций/деаллокаций свободная память фрагментирована. Redis решает это через zmalloc: объекты одного размера хранятся в слабах, нет фрагментации внутри slab. Nginx использует pool аллокатор per-request - всё освобождается разом после ответа.
Почему tcmalloc быстрее glibc malloc для многопоточного кода?
Arena Allocators
Arena (bump allocator, region allocator) - аллокация из непрерывного буфера через инкремент указателя. Освобождение - одна операция (сброс указателя или drop всей арены). Нет фрагментации, аллокация straightforwardly быстрая. Используется везде, где lifetime объектов совпадает: AST компилятора, JSON-парсинг, request в веб-сервере.
Rust bumpalo crate - production-grade bump allocator. Go compiler использует arena аллокаторы для IR nodes. LLVM BumpPtrAllocator выделяет память чанками и переключается на следующий чанк при переполнении. Ключевое ограничение: нельзя освободить отдельный объект - только всю арену.
Почему arena allocator недостаточен для общего случая (general-purpose)?
RAII: Resource Acquisition Is Initialization
RAII (C++, Bjarne Stroustrup) - ресурс привязан к времени жизни объекта. Деструктор вызывается автоматически при выходе из scope. Никаких утечек при исключениях. std::unique_ptr - RAII ownership, std::shared_ptr - RAII с reference counting, std::lock_guard - RAII mutex.
RAII полностью решает resource leak проблему для C++ при дисциплинированном использовании. Clang Tidy (cppcoreguidelines-*) статически проверяет использование raw pointers вместо RAII. Chrome codebase имеет scoped_refptr - собственные RAII wrappers с дополнительными проверками для безопасности браузера.
Что гарантирует RAII при возникновении исключения внутри функции?
Rust Borrow Checker
Rust borrow checker - compile-time анализ ownership и lifetimes. Правила: каждое значение имеет одного владельца; при передаче ownership перемещается (move); можно создать любое количество shared references (&T) или одну mutable reference (&mut T) - но не оба одновременно. Нарушение правил - ошибка компиляции, не runtime.
Android Open Source Project (AOSP) переводит C/C++ компоненты на Rust с 2021 года: Android 13+ имеет ~1.5M строк Rust. Цель - устранить 70% CVE связанных с memory safety (UAF, buffer overflow). Microsoft Azure переписывает части Windows Kernel на Rust. Chromium начал добавлять Rust компоненты в 2023 году.
Rust borrow checker делает любую программу автоматически быстрее за счёт отсутствия GC
Rust исключает GC-паузы, но программист платит временем на борьбу с borrow checker и иногда вынужден клонировать данные там, где GC-язык поделился бы ссылкой
Для некоторых алгоритмов (граф с циклами, двусвязный список) Rust требует unsafe код или Rc/RefCell, что нивелирует часть преимуществ. Rustonomicon документирует паттерны где безопасный Rust невозможен без unsafe
Почему Rust запрещает иметь &mut T и &T на один объект одновременно?
Итоги
- malloc/free с thread-local caches (tcmalloc, jemalloc): аллокация < 50ns, но фрагментация и overhead metadata ~16 bytes/block
- Arena allocators: bump pointer аллокация за 1-3 инструкции, O(1) освобождение всех объектов - идеально для AST, request-scope объектов
- Rust borrow checker: статическая гарантия memory safety без GC; XOR mutability исключает use-after-free и data races на этапе компиляции
Связанные темы
Управление памятью - основа для понимания GC и производительности компиляторов:
- Основы GC — GC автоматизирует то, что malloc/free делает вручную; понимание аллокаторов объясняет overhead GC
- Продвинутый GC — ZGC и Shenandoah - альтернатива ручному управлению памятью для managed языков
- Спекулятивные оптимизации — Escape analysis (JIT) определяет, можно ли аллоцировать объект на стеке вместо heap
Вопросы для размышления
- Rust borrow checker иногда требует клонировать данные там где Java использует shared reference. В каких структурах данных borrow checker создаёт наибольшие трудности?
- Arena аллокаторы требуют что все объекты имеют одинаковый lifetime. Как компиляторы (Clang, rustc) организуют арены, если AST узлы имеют разные lifetimes?
- Android переписывает C++ на Rust для memory safety. Какой overhead (performance, code size, developer productivity) это создаёт и как Google его измеряет?