# Аллокатор кучи **Файл**: `src/mem/allocator.rs` Slab-аллокатор со spinlock-синхронизацией и fallback bump-аллокацией для больших блоков. --- ## Примитив синхронизации: `Locked` Самодельный spinlock (альтернатива `spin::Mutex`). ```rust pub struct Locked { inner: UnsafeCell, lock: AtomicBool, } ``` - `new(inner)` — создаёт с unlocked состоянием - `lock() -> LockedGuard<'_, A>` — CAS-цикл на `AtomicBool` (спин-ожидание) ### LockedGuard - `Deref`/`DerefMut` — доступ к внутренним данным - `Drop` — `store(false, Release)` — освобождение блокировки `unsafe impl Sync for Locked` — разработчик гарантирует корректность. --- ## SlabAllocator ```rust pub struct SlabAllocator { list_heads: [Option<&'static mut ListNode>; 9], // slab free list large_block_free: Option<&'static mut LargeBlockNode>, // free list для >2048 heap_start: usize, heap_end: usize, next_bump: usize, } ``` ### Slab классы ```rust const BLOCK_SIZES: &[usize] = &[8, 16, 32, 64, 128, 256, 512, 1024, 2048]; ``` 9 классов — степени двойки от 8 до 2048. ### ListNode / LargeBlockNode ```rust struct ListNode { next: Option<&'static mut ListNode>, } struct LargeBlockNode { size: usize, next: Option<&'static mut LargeBlockNode>, } ``` Односвязные списки свободных блоков. ### `init(&mut self, start, size)` Устанавливает границы кучи: `heap_start = start`, `heap_end = start + size`, `next_bump = start`. ### `list_index(layout) -> Option` Находит индекс наименьшего slab-класса, покрывающего `max(size, align)`. Пример: layout size=20, align=8 → блок 20 > 16, следующий 32 → index 3 (32 байта). ### `fallback_alloc(&mut self, layout) -> *mut u8` 1. Проверяет `large_block_free` — если есть подходящий блок, отдаёт его 2. Иначе bump-аллокация: выравнивание, проверка `next_bump + size <= heap_end`, возврат `next_bump` 3. При OOM возвращает null --- ## Глобальный аллокатор ```rust #[global_allocator] pub static ALLOCATOR: Locked; ``` ### `GlobalAlloc::alloc(&self, layout) -> *mut u8` 1. Lock allocator 2. Если `layout.size()` влезает в slab класс: - Находит `list_index` - Если free list не пуст: pop голову, вернуть указатель - Если пуст: `fallback_alloc(layout)` но с размером slab-блока (не `layout.size()`) 3. Для блоков > 2048: сразу `fallback_alloc(layout)` ### `GlobalAlloc::dealloc(&self, ptr, layout)` 1. Lock allocator 2. Для slab-sized: push обратно в slab free list как ListNode 3. Для больших: push в large_block_free как LargeBlockNode