内存管理伙伴算法 模拟程序

#include <stdio.h>
#include<iostream>
using namespace std;
#include<list>
#include<math.h>
#include<string>
#include<ctype.h>
struct Block
{	
	int start;
	int end;
	Block()
	{
		start=0;
		end =0;
	}
	int operator<(Block b)
	{
		return this->end < b.start;
	}
};
#define BLOCKTYPE 10
struct MemBlock
{
	int num;
	int base;
	list<Block> memBlockList;
	MemBlock()
	{
		num = 0;
		base = 0;
		memBlockList.clear();
	}
};
struct Job
{
	int start;
	int end;
	int index;
	Job()
	{
		start=0;
		end =0;
	}
};
list<Job> jobList;
int jobindex = 0;
MemBlock arr[BLOCKTYPE];
bool isMemInit = false;//是否初始化过内存

//回收所有内存
void MemEnd()
{
	int i = 0;
	for(i = 0;i<BLOCKTYPE;i++)
	{
		arr[i].base = 0;
		arr[i].memBlockList.clear();
	}
	jobList.clear();
	jobindex = 0;
	isMemInit = false;
}

//初始化分配内存
void MemInit( int PoolSize )
{
	
	int i = BLOCKTYPE - 1;
	int n = 0;
	int j = 0;
	int base;
	for(;PoolSize >=8 && i>=0;i--)
	{
		base = (int)pow(2.0,i+3);
		arr[i].num = 0;
		n = PoolSize/base;
		PoolSize = PoolSize%base;
		if(n > 0)
		{
			arr[i].num = n;
			for(j = n;j>0;j--)
			{
				Block block;
				arr[i].memBlockList.push_back(block);				
			}
		}
	}
	int start = 0;
	int end = 0;
	list<Block>::iterator it;
	for(i = 0;i<BLOCKTYPE;i++)
	{
		base = (int)pow(2.0,i+3);
		arr[i].base = base;
		if(arr[i].num>0)
		{
			it = arr[i].memBlockList.begin();
			while(it != arr[i].memBlockList.end())
			{				
				end = start+base-1;
				(*it).start = start;
				(*it).end = end;
				start = end+1;
				it++;
			}
		}	

	}
	isMemInit = true;
}

//合并连续内存
void mergeMem(int index)
{
	int i = index;
	if(i>=	BLOCKTYPE -1)//超过最大了
	{
		return;
	}
	if(arr[i].num > 1)
	{
		list<Block>::iterator it1 = arr[i].memBlockList.begin();
		list<Block>::iterator it2 = arr[i].memBlockList.begin();
		it2++;
		while(it2 != arr[i].memBlockList.end())
		{
			if(it1->end == it2->start-1)
			{
				Block block;
				block.start = it1->start;
				block.end = it2->end;
				arr[i+1].memBlockList.push_back(block);
				arr[i+1].num++;
				arr[i].memBlockList.erase(it1);
				arr[i].memBlockList.erase(it2);
				arr[i+1].memBlockList.sort();
				arr[i].num--;
				arr[i].num--;
				break;
			}
			it1++;
			it2++;
		}
	}
	mergeMem(i+1);
}

//分割多余内存
void divdeMem(int start,int end,int index)
{
	int i = index;
	if(start > end)
	{
		//合并内存
		mergeMem(i+1);
		return;
	}

	Block block;
	block.end = end;
	block.start = end - arr[i].base+1;
	end = block.start -1;
	arr[i].memBlockList.push_back(block);
	arr[i].memBlockList.sort();
	arr[i].num++;
				
	divdeMem(start,end,i-1);
	

}



//申请内存
bool MemAlloc( int MemSize )
{
	if(MemSize > 4096 || MemSize < 1)
	{
		return false;
	}
	int size = 0;
	int i = 0;
	int n = 0;
	for(;i<BLOCKTYPE;i++)
	{
		if(MemSize <= arr[i].base)
		{
			if(0 == size)
			{
				size = arr[i].base;//实际分配的大小
			}
			
			//有空闲块
			if(arr[i].num > 0)
			{
				//空闲块链表应该是有序的
				Block block = arr[i].memBlockList.front();
				jobList.back().start = block.start;
				jobList.back().end = block.start+size-1;
				
				//分配了一块内存 
				arr[i].memBlockList.pop_front();
				arr[i].num--;
				
				//分割多余内存
				int start = block.start + size;
				int end = block.end;
				divdeMem(start,end,i-1);
				return true;
			}
			
		}		
	}
	return false;
}

//释放指定内存
void MemFree( int start,int end )
{
	int size = end - start +1;
	int i = 0;
	for(;i<BLOCKTYPE;i++)
	{
		if(arr[i].base == size)
		{
			Block block;
			block.start = start;
			block.end = end;
			arr[i].memBlockList.push_back(block);
			arr[i].memBlockList.sort();
			
			arr[i].num++;
			mergeMem(i);
			
		}
	}		
}
void menu()
{
	cout <<"空闲内存伙伴算法程序模拟" << endl;
	cout <<"1.初始化内存分配" << endl;
	cout <<"2.作业分配申请内存" << endl;
	cout <<"3.作业释放内存" << endl;
	cout <<"4.查看当前内存使用情况" << endl;
	cout <<"0.退出模拟程序" << endl;
}

//获得要初始化的内存大小
bool getRequestMem(int &n)
{
	if(isMemInit)
	{
		cout << "内存已经被初始化,将重新初始化分配内存,所有数据将会丢失,确定要继续吗,Y/N?" << endl;
		char c;
		cin >> c;
		if(toupper(c) == 'Y')
		{
			
		}
		else if(toupper(c) == 'N')
		{
			return false;
		}
		else
		{
			cout << "非法输入,返回主程序" << endl;
			return false;
		} 
		MemEnd();
	}
	cout << "请输入分配的内存大小" << endl;
	cin >> n;
	return true;	
}

//为作业分配内存
void assignMemForJob()
{
	Job job;
	job.index = jobindex++;
	jobList.push_back(job);
	cout << "请输入申请内存大小" << endl;
	int n;
	cin >> n;
	if(MemAlloc(n))
	{
		cout << "作业申请内存成功,起始地址为job" << job.index << ":" << jobList.back().start << "~" << jobList.back().end << endl;
	}
	else
	{
		jobindex--;
		jobList.pop_back();
		cout << "当前没有足够内存,请释放一定内存后再试" << endl;
	}
	
}

void checkMem()
{
	cout << "内存空闲块:" << endl;
	int i = 0;
	list<Block>::iterator it;	
	for(;i< BLOCKTYPE;i++)
	{
		printf("%d : 有%d个空闲内存块    起始地址分别为:",arr[i].base,arr[i].num);
		for(it = arr[i].memBlockList.begin();it!=arr[i].memBlockList.end();it++)
		{
			printf("%d~%d ",it->start,it->end);
		}
		printf("\n");
	}
	
	cout << "作业占用内存:" << endl;
	list<Job>::iterator job = jobList.begin();
	while(job != jobList.end())
	{
		printf("作业%d 大小:%d 内存地址:%d~%d\n",job->index,job->end - job->start+1,job->start,job->end);
		job++;
	}
}

//释放作业内存
void retrieveMemFromJob()
{
	cout << "请输入要释放的作业编号" << endl;
	int n = -1;
	cin >> n;
	if(n < 0)
	{
		cout << "不存在该编号的作业,作业释放内存失败" << endl;
	}
	else
	{
		list<Job>::iterator it = jobList.begin();
		
		while(it != jobList.end())
		{
			if(it->index == n)
			{
				Job job = *it;
				jobList.erase(it);
				
				//释放作业内存
				MemFree(job.start,job.end);
				break;
			}
			it++;			
		}
		cout << "作业释放内存成功" << endl;
	}
}
int main()
{
	
	int choice = -1;
	int size = 0;

	while(1)
	{
		menu();
		cin >> choice;
		if(0 == choice)
		{
			break;
		}
		switch(choice)
		{
			case 1:				
				if(getRequestMem(size))
				{
					MemInit(size);
					cout << "初始化内存成功" << endl;
				}
				else
				{
					cout << "初始化内存失败" << endl;
				}			
				break;
			case 2:
				assignMemForJob();
				break;
			case 3:
				retrieveMemFromJob();
				break;
			case 4:
				checkMem();
				break;
			default:
				cout << "非法选项" << endl;
				break;			
		}

	}
	cout << "退出模拟程序" << endl;
	return 0;
}

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
这个内存分配器需要是非入侵式的,即不在要分配的内存块中写 cookie 。 而我的需求中,需要被管理的内存块都是很规则的,成 2 的整数次幂的长度。buddy memory allocation 刚好适用。 算法很简单,就是每次把一个正内存块对半切分,一直切到需要的大小分配出去。回收的时候,如果跟它配对的块也是未被使用的,就合并成一个大的块。标准算法下,分配和释放的时间复杂度都是 O(log N) ,N 不会特别大。算法的优点是碎片率很小。而且很容易做成非入侵式的,不用在被管理的内存上保存 cookie 。只需要额外开辟一个二叉树记录内存使用状态即可。 我吃完饭简单 google 了一下,没有立刻找到满足我要求的现成代码。心里估算了一下,C 代码量应该在 200 行以下,我大概可以在 1 小时内写完。所以就毫不犹豫的实现了一份。 然后,自然是开源了。有兴趣的同学可以去 github 拿一份。这样就省得到再需要时再造轮子了。嘿嘿。 btw, 当然这块代码有许多值得优化的地方,比如可以把里面的递归优化成循环回溯。这个算法我读初中时经常写。因为初一那个时候参加信息学奥赛时用的 basic 不支持局部变量,全部变量都是全局的,很难实现递归。所以早期我都不用递归遍历二叉树的,感觉写起来好麻烦。 不过循环回溯遍历树应该是比递归快不少的,因为减少了许多不必要的环境变量压栈,对不支持 closure 的 C 语言尤其是。 这个库用起来很简单。它并不实际管理内存(它不侵入被管理的内存)。你可以设想你另外有一大块内存是由许多最小单位块合起来的。你可以假设最小单位是 1K 。那么用 buddy_new(10) 就可以帮你管理 1024K 内存。 buddy_alloc 可以请求若干个最小单位块,返回一个序号。然后用户可以自己去大内存上索引出来用。用完调用 buddy_free 归还即可。 为了调试方便,我还提供了 buddy_dump 打印二叉树的细节,可以直观的看出那些内存区域未被使用,哪些已经被占用。 ps. 果然,写这篇 blog 花掉的时间比完成这些代码时间更长。代码也如我所料的没有超过 200 行。看看,把东西描述清楚就是比实现一个东西要花更长的时间,这就是项目人多反而做的慢的原因之一吧。
好的,下面是一个简单的内存管理模拟程序的伪代码: ``` // 定义常量 const int MEMORY_SIZE = 1024; // 内存大小 const int PARTITION_SIZE = 64; // 分区大小 // 定义全局变量 int memory[MEMORY_SIZE]; // 内存数组 bool is_allocated[MEMORY_SIZE / PARTITION_SIZE]; // 记录每个分区是否已分配 int num_partitions = MEMORY_SIZE / PARTITION_SIZE; // 分区数量 // 初始化内存 for (int i = 0; i < MEMORY_SIZE; i++) { memory[i] = 0; } // 初始化分区状态 for (int i = 0; i < num_partitions; i++) { is_allocated[i] = false; } // 定义函数:分配内存 int allocate_memory(int size) { int num_partitions_needed = ceil(size / PARTITION_SIZE); // 计算需要的分区数量 int start_partition = -1; // 记录起始分区编号 // 查找连续的未分配分区 int count = 0; for (int i = 0; i < num_partitions; i++) { if (!is_allocated[i]) { count++; if (count == num_partitions_needed) { start_partition = i - count + 1; break; } } else { count = 0; } } // 如果找到连续的未分配分区,进行内存分配 if (start_partition != -1) { for (int i = start_partition; i < start_partition + num_partitions_needed; i++) { is_allocated[i] = true; } return start_partition * PARTITION_SIZE; // 返回起始地址 } else { return -1; // 内存不足,分配失败 } } // 定义函数:释放内存 void free_memory(int addr, int size) { int start_partition = addr / PARTITION_SIZE; // 计算起始分区编号 int num_partitions_to_free = ceil(size / PARTITION_SIZE); // 计算需要释放的分区数量 // 释放内存 for (int i = start_partition; i < start_partition + num_partitions_to_free; i++) { is_allocated[i] = false; } } // 测试内存分配和释放 int main() { // 分配一块大小为 256 的内存 int addr1 = allocate_memory(256); if (addr1 != -1) { cout << "分配成功,地址为:" << addr1 << endl; } else { cout << "分配失败,内存不足!" << endl; } // 分配一块大小为 128 的内存 int addr2 = allocate_memory(128); if (addr2 != -1) { cout << "分配成功,地址为:" << addr2 << endl; } else { cout << "分配失败,内存不足!" << endl; } // 释放第一块内存 free_memory(addr1, 256); cout << "已释放地址为 " << addr1 << " 的内存" << endl; // 再次尝试分配一块大小为 256 的内存 int addr3 = allocate_memory(256); if (addr3 != -1) { cout << "分配成功,地址为:" << addr3 << endl; } else { cout << "分配失败,内存不足!" << endl; } return 0; } ``` 这是一个简单的内存管理模拟程序,它使用了“固定分区大小”的分配算法。当需要分配一块内存时,它会查找连续的未分配分区,如果找到了足够大的空间,就进行内存分配;否则分配失败。在释放内存时,它会根据起始地址和内存大小计算需要释放的分区数量,并将这些分区标记为未分配状态。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值