第9天 内存管理

内存管理有内存分配和内存释放两部分。

我们假设现在有128M内存可以使用,且将这些内存分块,每块为4KB,那么,共有32768个块。书中列举了两种方法来管理这些块。

1、用char table[32768]来保存内存的分配情况,如果第i块用了,则char[i] = '1',否则为'0'

class MEMBLOCKS
{
private:
	static const unsigned int MAX_MEM_BLOCKS = 32768;						//最大的内存块数
	static const unsigned int PER_MEM_BLOCK = 4 * 1024;						//每块的大小为4KB
	static const unsigned int MEM_SUM = MAX_MEM_BLOCKS * PER_MEM_BLOCK;		//总字节数,即总的可用内存
	unsigned int addr;														//初始化时申请到的内存的初始地址
	char table[MAX_MEM_BLOCKS];												//记录可用块
	int get_block_id(int addr);												//根据addr得出块号
public:
	MEMBLOCKS();
	int allocate(int size);		//分配size字节的内存并返回地址,分配失败返回0
	int free(unsigned int addr,unsigned int size);//释放内存
};

MEMBLOCKS::MEMBLOCKS()
{
	addr = 0x00ffff;
	for(int  i = 0;i < MAX_MEM_BLOCKS;i++)
		table[i] = '0';
}

int MEMBLOCKS::allocate(int size)
{
	if(size <= 0)
		return 0;
	int sum,i;
	sum = i = 0;
	while(1)
	{
		int tmp = i;
		sum = 0;
		while(i < MAX_MEM_BLOCKS && table[i] == '0' && sum < size)
		{
			sum += PER_MEM_BLOCK;
			i++;
		}
		if(sum >= size)
		{
			int addr = this->addr + tmp * PER_MEM_BLOCK;
			while(tmp <= i)
				table[tmp++] = '1';
			return addr;
		}
		if(i >= MAX_MEM_BLOCKS)
			return 0;
		i++;
	}
	return 0;
}

int MEMBLOCKS::free(unsigned int addr,unsigned int size)
{
	int lid = get_block_id(addr);
	int rid = get_block_id(addr + size - 1);
	if(lid < 0)
		return -1;
	while(lid <= rid && lid < MAX_MEM_BLOCKS)
		table[lid++] = '0';
	return 1;
}

int MEMBLOCKS::get_block_id(int addr)
{
	return (addr - this->addr) / PER_MEM_BLOCK;
}
这种分配方式是以块为单位来分配的,每次找到连续的块,它们的内存数量和大于用户需要的,则分配,且将相应的table[i]改成'1';如果遍历table都找不到,则分配失败;而在释放的时候,每次都是将释放的内存的块改成'0'。

我们可以计算出,这种方式,table的占用内存为32KB。在table的空间优化上,我们还可以用另一种方式:用bit位来表示内存的分配情况,那么char为1个字节,即8位,就可以表示8个块的内存使用情况,这样的话,我们只要用4096个char就可以了,那么,它占用的内存为4KB。不过这种方式在实现的时候有点难度,还没想到好办法。

2、用数组来表示。

如下面代码,定义了struct FREEMEM,它有两个属性,addr和size,分别表示该可用内存块的起始地址和大小。每次在分配的时候,如果需要分配的字节数小于等于能找到的最大可用块,那么就找一个这种可用块分配给它;而如果找不到的话,就需要将各个块连在一起,看连续的块(地址也要连续)能否满足分配的要求,如果不能就分配失败。在释放的时候,先将块按这个块应该所在的块号拆分(如果有的话),加到freemems数组中去,然后按地址进行排序,最后合并块,即地址连续有着同一个块号的freemems合并成一个。

这种方法分配的时候,并不是按4KB来分配的,而是按需分配,要多少,给多少,不会多给1字节。但这就引起了内存的碎片化非常严重,碎片太多可能会导致freemems不够用,我的程序还没有进行这样的处理。且分配的时候,可能分配的内存不在同一个块中,则需要将这个分配的内存拆分,分别释放。

class MEMBLOCKS
{
private:
	static const unsigned int MAX_MEM_BLOCKS = 32768;						//最大的内存块数
	static const unsigned int PER_MEM_BLOCK = 4 * 1024;						//每块的大小为4KB
	static const unsigned int MEM_SUM = MAX_MEM_BLOCKS * PER_MEM_BLOCK;		//总字节数,即初始化时要申请的内存字节数
	unsigned short num;														//块总数
	unsigned int min_block;													//最小块的字节数
	unsigned int max_block;													//最大块的字节数
	unsigned int addr;														//初始化时申请到的内存的初始地址
	struct FREEMEM
	{
		/**
		 *addr: 可用内存的起始地址
		 *size: 从该起始地址起有size字节的内存可用
		 **/
		unsigned int addr,size;
	}freemems[MAX_MEM_BLOCKS];

	int get_block_id(int addr);	//得到块号,这里块号的定义是(addr - this->addr) / PER_MEM_BLOCK,即初始时freemems[num]中的i
	int update_max_block();		//更新最大块max_block
	void move_blocks(int start,int n);			//移动块,即freemems[start + x] = freemems[start + n + x]
public:
	MEMBLOCKS();
	int allocate(int size);		//分配size字节的内存并返回地址,分配失败返回0
	int free(unsigned int addr,unsigned int size);//释放内存
	void show_blocks();			//输出当前块的情况
	~MEMBLOCKS();
};

MEMBLOCKS::MEMBLOCKS()
{
	//addr =	new int[MEM_SUM / 1024];
	addr = 0x00ffff;
	if(!addr)
	{
		cout << "Initialization failed!" << endl;
		return;
	}
	num = MAX_MEM_BLOCKS;
	max_block = min_block = PER_MEM_BLOCK * 1024;
	for(int i = 0;i < num;i++)
	{
		freemems[i].addr = addr + PER_MEM_BLOCK * i;
		freemems[i].size = PER_MEM_BLOCK;
	}
	show_blocks();
}

int MEMBLOCKS::allocate(int size)
{
	if(size <= 0 || !num)
		return 0;
	//更新最大块
	update_max_block();
	if(size > max_block)
	{
		//申请的内存比现存的最大块还大时,看能否合并块,能的话就分配,不能就分配失败
		for(int i = 0;i < num;)
		{
			int sum,j;
			sum = freemems[i].size,j = i + 1;
			while(j < num && freemems[j - 1].addr + freemems[j - 1].size == freemems[j].addr)
			{
				sum += freemems[j].size;
				if(sum >= size)
				{
					//最后一块一部分分配出去
					if(sum - size > 0)
					{
						freemems[j].addr = freemems[j].addr + freemems[j].size - (sum - size);
						freemems[j].size = sum - size;
						j--;
					}
					break;
				}
				j++;
			}
			if(sum >= size)//合并
			{
				//cout << "i: " << i << endl;
				//cout << "j: " << j << endl;
				int m = freemems[i].addr;
				int tmp = j - i + 1;
				move_blocks(i,tmp);
				show_blocks();
				return m;
			}
			//没找到合并点
			i = j + 1;
		}
		return 0;
	}
	else
	{
		for(int i = 0;i < num;i++)
			if(freemems[i].size >= size)
			{
				int tmp = freemems[i].addr;
				freemems[i].addr += size;
				freemems[i].size -= size;
				if(!freemems[i].size)
					move_blocks(i,1);
				show_blocks();
				return tmp;
			}
		return 0;
	}
	return 0;
}

int MEMBLOCKS::free(unsigned int addr,unsigned int size)
{
	int laddr,raddr;
	while(size > 0)
	{
		laddr = get_block_id(addr);
		raddr = get_block_id(addr + size - 1);
		//cout << "laddr: " << laddr << endl;
		//cout << "raddr: " << raddr << endl;
		if(laddr == raddr)
		{
			freemems[num++] = {addr,size};
			size = 0;
		}
		else
		{
			int tmp = (laddr + 1) * PER_MEM_BLOCK + this->addr - addr;
			size -= tmp;
			freemems[num++] = {addr,tmp};
			addr += tmp;
			//cout << "addr: " << addr << endl;
		}
	}

	//排序
	for(int i = 0;i < num;i++)
		for(int j = i + 1;j < num;j++)
			if(freemems[i].addr > freemems[j].addr)
			{
				FREEMEM tmp = freemems[i];
				freemems[i] = freemems[j];
				freemems[j] = tmp;
			}
	//合并本应是一个块且内存连续的
	for(int i = 1;i < num;i++)
		if(get_block_id(freemems[i - 1].addr) == get_block_id(freemems[i].addr))
		{
			freemems[i - 1].size += freemems[i].size;
			move_blocks(i,1);
			i--;	//保证下一次循环中i在当前位置不变
		}
	show_blocks();
	return 1;
}

int MEMBLOCKS::update_max_block()
{
	max_block = 0;
	for(int i = 0;i < num;i++)
		if(max_block < freemems[i].size)
			max_block = freemems[i].size;
	return max_block;
}

int MEMBLOCKS::get_block_id(int addr)
{
	return (addr - this->addr) / PER_MEM_BLOCK;
}

void MEMBLOCKS::move_blocks(int start,int n)
{
	num -= n;
	for(int i = start;i < num;i++)
		freemems[i] = freemems[i + n];
}

void MEMBLOCKS::show_blocks()
{
	cout << "num of blocks: " << num << endl;
	for(int i = 0;i < num;i++)
		cout << i << ": " << "{" << freemems[i].addr << ", " << freemems[i].size << "}" << endl;
	cout << endl;
}

MEMBLOCKS::~MEMBLOCKS()
{
	//delete []addr;
}

int main()
{
	int size,addr;
	MEMBLOCKS mem;
	while(cin >> addr >> size)
	{
		if(!addr)
		{
			int tmp = mem.allocate(size);
			if(tmp)
				cout << "allocate successfully! " << tmp << endl;
			else
				cout << "allocate failed!" << endl;
		}
		else
			mem.free(addr,size);
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值