Compilers
Manual memory management
70% of all CVEs in Chrome, Android, and Windows come from memory management bugs: use-after-free, buffer overflow, double-free. Not because the developers are inexperienced, but because C/C++ provide no tools for static checking. The Rust borrow checker makes these bug classes impossible at compile time. That is why Microsoft, Google, and Android are rewriting system code in Rust.
- **jemalloc** in Rust std and Firefox: heap fragmentation reduced by 20-40% compared to glibc malloc, especially noticeable in long-running processes
- **LLVM BumpPtrAllocator**: Clang allocates ~90% of AST nodes through a bump allocator. One of the reasons Clang compiles faster than GCC
- **Android 13+**: about 1.5M lines of Rust in AOSP, including the Bluetooth stack and Keystore2. Since 2021, zero memory-safety CVEs in Rust components
malloc/free and allocators
malloc (memory allocator) manages the heap through lists of free blocks. The glibc malloc (ptmalloc2) uses bins: small bins for 16-504B blocks, large bins for bigger ones, and an unsorted bin as a buffer. On free(), the block returns to its bin and merges with neighbours when possible. Every block carries 8-16 bytes of metadata overhead.
Heap fragmentation is a practical problem. After millions of allocations and deallocations, free memory becomes fragmented. Redis solves this with zmalloc: objects of the same size live in slabs with no intra-slab fragmentation. Nginx uses a per-request pool allocator and frees everything at once after the response is sent.
Why is tcmalloc faster than glibc malloc for multithreaded code?
Arena allocators
An arena (also bump allocator or region allocator) allocates from a contiguous buffer by incrementing a pointer. Freeing is one operation (reset the pointer or drop the whole arena). No fragmentation, and allocation is very fast. It is used everywhere object lifetimes coincide: compiler ASTs, JSON parsing, requests in a web server.
The Rust bumpalo crate is a production-grade bump allocator. The Go compiler uses arena allocators for IR nodes. LLVM BumpPtrAllocator allocates memory in chunks and moves on to the next chunk when one fills up. The key limitation: you cannot free a single object, only the whole arena.
Why is an arena allocator not sufficient for general-purpose use?
RAII: Resource Acquisition Is Initialization
RAII (C++, Bjarne Stroustrup) ties a resource to the lifetime of an object. The destructor is called automatically when the scope exits. No leaks on exceptions. std::unique_ptr is RAII ownership, std::shared_ptr is RAII with reference counting, std::lock_guard is an RAII mutex.
RAII fully solves resource leaks in C++ when used with discipline. Clang Tidy (cppcoreguidelines-*) statically checks for raw pointers used in place of RAII. The Chrome codebase has scoped_refptr, custom RAII wrappers with extra checks for browser security.
What does RAII guarantee when an exception is thrown inside a function?
Rust borrow checker
The Rust borrow checker is compile-time analysis of ownership and lifetimes. The rules: every value has one owner; passing ownership moves it; you can have any number of shared references (&T) or a single mutable reference (&mut T), but not both at once. Violations are compile errors, not runtime ones.
The Android Open Source Project (AOSP) has been porting C/C++ components to Rust since 2021. Android 13+ contains about 1.5M lines of Rust. The goal is to eliminate 70% of CVEs related to memory safety (UAF, buffer overflow). Microsoft Azure is rewriting parts of the Windows Kernel in Rust. Chromium started adding Rust components in 2023.
The Rust borrow checker automatically makes every program faster by removing GC
Rust eliminates GC pauses, but you pay in time spent fighting the borrow checker and in cases where data must be cloned where a GC language would share a reference
For some algorithms (a graph with cycles, a doubly linked list) Rust requires unsafe code or Rc/RefCell, which gives up part of the advantage. The Rustonomicon documents patterns where safe Rust is impossible without unsafe
Why does Rust forbid having &mut T and &T to the same object at the same time?
Key ideas
- malloc/free with thread-local caches (tcmalloc, jemalloc): allocation under 50ns, but fragmentation and 16 bytes/block of metadata overhead
- Arena allocators: bump pointer allocation in 1-3 instructions, O(1) free of every object. Ideal for ASTs and request-scoped objects
- The Rust borrow checker: a static guarantee of memory safety without GC. XOR mutability rules out use-after-free and data races at compile time
Related topics
Memory management is the foundation for understanding GC and compiler performance:
- GC basics — GC automates what malloc/free does by hand. Understanding allocators explains GC overhead
- Advanced GC — ZGC and Shenandoah are alternatives to manual memory management for managed languages
- Speculative optimizations — Escape analysis (in the JIT) decides whether an object can live on the stack instead of the heap
Вопросы для размышления
- The Rust borrow checker sometimes forces cloning where Java uses a shared reference. Which data structures cause the most trouble for the borrow checker?
- Arena allocators require every object to share a lifetime. How do compilers (Clang, rustc) organize arenas when AST nodes have different lifetimes?
- Android is rewriting C++ in Rust for memory safety. What overhead (performance, code size, developer productivity) does this create, and how does Google measure it?