Open huangchunzhen opened 5 years ago
Lab2:物理内存管理的buddy-allocator代码
#![feature(alloc)]
#![no_std]
#![feature(lang_items)]
extern crate alloc;
use alloc::vec::Vec;
use core::alloc::Layout;
pub struct BuddyAllocator {
nodes : Vec<i8>,
level : u8,
}
impl BuddyAllocator {
pub fn new() -> Self {
let ret = BuddyAllocator{
nodes : Vec::new(),
level : 0,
};
ret
}
pub fn init(&mut self, level : u8) {
self.level = level;
let mut idx = 0;
for s in 0..level {
for _t in 0..(1 << s) {
self.nodes.push(0_i8);
self.nodes[idx] = ( level - s - 1 ) as i8;
idx = idx + 1;
}
}
}
pub fn alloc(&mut self, alloc_size : usize) -> Option<usize> {
let size = log2_up(alloc_size) as i8;
let mut location = 0;
let mut height = self.level - 1;
let ret;
while height != 0 {
if size > self.nodes[location] {
panic!("memory is not enough ");
}
if self.nodes[(location << 1) + 1] >= size {
location = (location << 1) + 1;
}else if self.nodes[(location + 1) << 1] >= size{
location = (location + 1) << 1;
}else{
break;
}
height = height - 1;
}
ret = (location + 1) * (1 << height) - (1 << (self.level - 1));
self.nodes[location] = -1;
while location > 0 { // 回溯,更新父辈节点
if location & 0x1 > 0 { // 当前节点的下标为奇数
if self.nodes[location] > self.nodes[location + 1] { // 当前节点的值大于兄弟节点的值
self.nodes[location >> 1] = self.nodes[location];
}else{ // 兄弟节点的值不小于当前节点的值
self.nodes[location >> 1] = self.nodes[location + 1];
}
location = location >> 1;
}else{ //当前节点的下标为偶数
if self.nodes[location] > self.nodes[location - 1] {
self.nodes[(location - 1) >> 1] = self.nodes[location];
}else{
self.nodes[(location - 1) >> 1] = self.nodes[location - 1];
}
location = (location - 1) >> 1;
}
}
Some(ret)
}
pub fn dealloc(&mut self, address : usize, dealloc_size : usize){
let size = log2_down(dealloc_size) as i8;
let mut location = address + (1 << (self.level - 1)) - 1;
let mut height = 0_i8;
while size > height {
height += 1;
location = if location & 0x1 == 0 {
(location - 1) >> 1
}else{
location >> 1
};
}
self.nodes[location] = size as i8;
while location > 0 {
if location & 0x1 > 0 { // 奇数下标
if self.nodes[location] == self.nodes[location + 1] && self.nodes[location] == height{
self.nodes[location >> 1] = self.nodes[location] + 1;
}else if self.nodes[location] > self.nodes[location >> 1] {
self.nodes[location >> 1] = self.nodes[location];
}
location = location >> 1;
}else{ // 偶数下标
if self.nodes[location] == self.nodes[location - 1] && self.nodes[location] == height{
self.nodes[(location - 1) >> 1] = self.nodes[location] + 1;
}else if self.nodes[location] > self.nodes[(location - 1) >> 1]{
self.nodes[(location - 1) >> 1] = self.nodes[location];
}
location = (location - 1) >> 1;
}
height = height + 1;
}
}
}
#[inline(always)]
fn log2_up(x: usize) -> usize { // 以2为底的对数向上取整的值,主要考虑分配内存时应该向上取整
assert_ne!(x, 0);
let mut temp_x = x;
let mut pos = -1;
while temp_x != 0 {
pos += 1;
temp_x >>= 1;
}
if x - (1 << pos) != 0 {
pos = pos + 1;
}
pos as usize
}
#[inline(always)]
pub fn log2_down(x: usize) -> usize { // 以2为底的对数向下取整的值,释放内存时向下取整
assert_ne!(x, 0);
let mut temp_x = x;
let mut pos = -1;
while temp_x != 0 {
pos += 1;
temp_x >>= 1;
}
pos as usize
}
#[lang = "oom"]
fn oom(_: Layout) -> ! {
panic!("out of memory");
}
lab2代码是对于buddy-allocator的一个简单实现,使用的是Rust编程语言。在对buddy-allocator进行阐述之前,我们先对buddy-allocator有个大概了解,wiki上是这么解释的:
The buddy memory allocation technique is a memory allocation algorithm that divides memory into partitions to try to satisfy a memory request as suitably as possible. This system makes use of splitting memory into halves to try to give a best fit. According to Donald Knuth, the buddy system was invented in 1963 by Harry Markowitz, and was first described by Kenneth C. Knowlton (published 1965). The Buddy memory allocation is relatively easy to implement. It supports limited but efficient splitting and coalescing of memory blocks.
注意其中这么几句话:
The Buddy memory allocation is relatively easy to implement. It supports limited but efficient splitting and coalescing of memory blocks.
它说的是 limited & efficient,那么它的 limited 和 efficient 又体现在哪儿呢?
首先我们从代码入手来查看buddy-allocator
的思路:
我们通过fn new() -> Self
和fn init(&mut self, level : u8)
知道buddy-allocator
是采用(完全)二叉树形式,在初始化时为各节点标号+赋值(0),通过各节点来track各物理内存块。以深度为4的完全二叉树举例:树根向下依次为3,2,1,0:3层1个节点,标号为0;2层2个标号为1,2;1层4个节点,标号为3,4,5,6以此内推,(level-1)层只有一个节点,即根节点。我们先不急着看fn alloc(&mut self, alloc_size : usize) -> Option<usize>
和fn dealloc(&mut self, address : usize, dealloc_size : usize)
,而是把目光转向fn log2_down(x: usize) -> usize
和fn log2_down(x: usize) -> usize
。这两个函数依次用于分配内存和释放内存的函数中,原因可见注释,具体原理我们稍后解释。
就以fn log2_down(x: usize) -> usize
举例:首先判断所传参数size
是否为0,然后连续左移N次来判断其层级,最后将层级返回。
在fn alloc(&mut self, alloc_size : usize) -> Option<usize>
得到fn log2_down(x: usize) -> usize
传递的参数size后,就开始进行循环判断。初始条件是if size > self.nodes[location]
,即若所需空间大小超过了所能容纳空间的最大大小,就panic!("memory is not enough ");
。
if self.nodes[(location << 1) + 1] >= size {
location = (location << 1) + 1;
}else if self.nodes[(location + 1) << 1] >= size{
location = (location + 1) << 1;
为分别判断到某一结点时是否满足size > 该node空间的情况。若不是,则继续 location = (location << 1) + 1
向下左子树查询,不然就location = (location + 1) << 1;
向下右子树查询,直到某节点的左右子树都不可向下继续迭代时,该节点才是最终确定的节点。这时才break掉。height跟踪最终所定位的层级数,height-1
是因为要去掉根节点。
由于准备引入slab allocation算法,但是一直被卡,一是Rust的指针问题,二是感觉没有理解slab allocation,于是决定先放弃代码,沉住气来看看《计算机程序设计艺术(第一卷)》的2.5 动态存储分配和slab allocation
https://people.eecs.berkeley.edu/~kubitron/courses/cs194-24-S14/hand-outs/bonwick_slab.pdf 的论文,随后再更新best fit
,first fit
,last fit
的实现代码 与 buddy-allocator
和slab allocation
的代码理解和原理解读。
The slab allocator has three principle aims:
The allocation of small blocks of memory to help eliminate internal fragmentation that would be otherwise caused by the buddy system;
The caching of commonly used objects so that the system does not waste time allocating, initialising and destroying objects.
The better utilisation of hardware cache by aligning objects to the L1 or L2 caches.
该issue主要记录在Rcore实现上遇到的一些Rust问题,但主要以Rcore的代码实现为基础。在Rcore实现的途中会对 https://github.com/huangchunzhen/Tcore/issues/5 与该issue进行整理:该issue以代码实现与解读为主,https://github.com/huangchunzhen/Tcore/issues/5 以算法分析与优化(如果可能的话)为主。 Rcore参考资料: Rcore_step_by_step : https://github.com/LearningOS/rcore_step_by_step tutorial : https://github.com/rcore-os/rCore/wiki/tutorial