内存分配器

本节介绍堆内存分配器和物理页帧分配器

堆内存分配器和物理页帧分配器都使用了rcore社区提供的开源库 物理页帧分配器 堆内存分配器

物理页帧分配

/// 使用bitmap_allocator库定义全局BIT_ALLOCATOR
static BIT_ALLOCATOR: Mutex<BitAlloc256M> = Mutex::new(BitAlloc256M::DEFAULT);

/// 初始化页帧分配器
pub fn init(memory_regions: &'static mut MemoryRegions) {
    let mut ba = BIT_ALLOCATOR.lock();
    println!("[Kernel] Memory regions:");
    for region in memory_regions.into_iter() {
        println!("    {:x?}", region);
        if region.kind == MemoryRegionKind::Usable {
            let start = region.start as usize;
            let end = region.end;
            let start_frame = start as usize / PAGE_SIZE;
            let end_frame = end as usize / PAGE_SIZE;
            ba.insert(start_frame..end_frame);
        }
    }
}

impl PhysFrame {
    /// 分配一个物理页帧
    pub fn alloc() -> Option<Self> {
        allocate_frame().map(Self)
    }
}

impl Drop for PhysFrame {
    /// drop时释放掉物理页帧占的位
    fn drop(&mut self) {
        deallocate_frame(self.0);
    }
}

我们使用了一个基于位图实现的物理页帧分配器,利用bootloader启动后传入的内存区域信息初始化位图。

物理页帧由内核显式地分配,需要一个新的页帧时使用alloc()方法分配,而由编译器隐式地释放,释放时调用drop()方法,释放掉页帧对应的bit。

堆内存分配

use buddy_system_allocator::Heap;

struct LockedHeap(Cell<Heap<32>>);
#[global_allocator]
static HEAP_ALLOCATOR: LockedHeap = LockedHeap(Cell::new(Heap::new()));

我们使用了一个带伙伴系统的堆内存分配器(来自第三方库),使用#[global_allocator]将其注册为全局堆内存分配器。

#[global_allocator]
static HEAP_ALLOCATOR: LockedHeap<32> = LockedHeap::empty();

#[alloc_error_handler]
pub fn handle_alloc_error(layout: core::alloc::Layout) -> ! {
    panic!("Heap allocation error, layout = {:?}", layout);
}

static mut HEAP_SPACE: [u8; KERNEL_HEAP_SIZE] = [0; KERNEL_HEAP_SIZE];

pub fn heap_init() {
    unsafe {
        HEAP_ALLOCATOR
            .lock()
            .init(HEAP_SPACE.as_ptr() as usize, KERNEL_HEAP_SIZE);
    }
}

为其实现了GlobalAlloctrait后,内核中即可使用动态内存结构,而具体内存分配和释放是由Rust编译器插入代码来实现的。