buddy system

#ifndef PUBLIC_UTILITY
#define PUBLIC_UTILITY
#include <stdio.h>
#include <sys/sysinfo.h>
#include <vector>
#include <algorithm>
namespace publicutility
{
using namespace std;
class PublicUtility
{
public:
	/*
	 * @brief adjust odd elements to locate before even elements
	 * */
	static void Odd_before_Even(vector<int>&);
	/*
	 * @brief judge wheter a number is odd
	 * */
	inline static bool IsOdd(int num) 
	{
		return num & 1;
	}
	/*
	 * @brief judge whether the num is to pwoer like 2 4 8 16 ...
	 * */
	inline static bool ToPower(size_t num)
	{
		return 0 == (num & (num -1));
	}
	/*
	 * @brief get the free random
	 * @return K free memory 
	 * */
	inline static unsigned long GetFreeRam() 
	{
		struct sysinfo s_info;
		if(sysinfo(&s_info)) return 0;
		
		return s_info.freeram;
	}
	/*
	 * @brief fix the number to the minimal to power number such as num = 3 then return 4 num = 67 return 128
	 * */
	inline static unsigned FixToPower(unsigned num)
	{
		if(ToPower(num)) return num;
		num |= (num >> 1);					// make top 2 bit to be 1 11xx xxxx xxxx xxxx xxxx xxxx xxxx xxxx
		num |= (num >> 2);					// make top 4 bit to be 1 1111 xxxx xxxx xxxx xxxx xxxx xxxx xxxx
		num |= (num >> 4);					// make top 8 bit to be 1 1111 1111 xxxx xxxx xxxx xxxx xxxx xxxx
		num |= (num >> 8);					// make top 16 bit to be 1 1111 1111 1111 1111 xxxx xxxx xxxx xxxx
		num |= (num >> 16);					// make top 32 bit to be 1 1111 1111 1111 1111 1111 1111 1111 1111

		return num + 1;
	}
};
}
#endif

#include "PublicUtility.h"
namespace publicutility
{
/*
 * @brief adjust odd elements to locate before even elements
 * */
void PublicUtility::Odd_before_Even(vector<int>&v)
{
	int nlow = 0;
	int nhigh = v.size() - 1;
	bool blow_is_odd = false;
	bool bhigh_is_odd = false;
	bool blow_is_change = true;
	bool bhigh_is_change = true;
	while(nlow < nhigh)
	{
		if(blow_is_change)
		{
			blow_is_odd = IsOdd(v[nlow]);
			blow_is_change = false;
		}
		if(bhigh_is_change)
		{
			bhigh_is_odd = IsOdd(v[nhigh]);
			bhigh_is_change = false;
		}
		if(!blow_is_odd && bhigh_is_odd)
		{
			swap(v[nlow++], v[nhigh--]);
			blow_is_change = true;
			bhigh_is_change = true;
		}
		else
		if(!blow_is_odd && !bhigh_is_odd)
		{
			nhigh--;
			bhigh_is_change = true;
		}
		else
		if(blow_is_odd && bhigh_is_odd)
		{
			nlow++;
			blow_is_change = true;
		}
		else
		{
			nlow++;
			nhigh--;
			blow_is_change = true;
			bhigh_is_change = true;
		}
	}
}
}

/****************************************************************************
@File Name: buddysystem.h
@Author: wangzhicheng
@mail: 2363702560@qq.com
@Created Time: Wed 15 Feb 2017 01:54:36 PM CST
			   2017-02-20
****************************************************************************/
#ifndef BUDDY_SYSTEM_H
#define BUDDY_SYSTEM_H
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <vector>
#include <mutex>
#include <algorithm>
#include "PublicUtility.h"
namespace buddysystem
{
using namespace publicutility;
class FreeException
{
public:
	FreeException()
	{
		fprintf(stderr, "free exception...!\n");
	}
};
class BuddySystem
{
private:
	unsigned m_nCapacity;				// total memory 
	vector<unsigned>m_vecTree;			// full binary tree for storing each memory block
	void *m_pBasePtr;					// pointer to a memory zone
	mutex m_gmutex;
private:
	/*
	 * @brief get the current node of parent
	 * */
	inline int Parent(int current)
	{
		return (current - 1) >> 1;
	}
	/*
	 * @brief get the current index of lchild
	 * */
	inline int Lchild(int current)
	{
		return (current << 1) + 1;
	}
	/*
	 * @brief get the current index of rchild
	 * */
	inline int Rchild(int current)
	{
		return (current << 1) + 2;
	}
public:
	BuddySystem():m_pBasePtr(0)
	{
	}
	~BuddySystem()
	{
		if(m_pBasePtr)
		{
			free(m_pBasePtr);
	//		m_pBasePtr = 0;
		}
	}
	/*
	 * @brief initialize the buddy system
	 * @cap the memory capacity unit:Byte
	 * @return true if init ok
	 * */
	bool Init(unsigned cap);
	/*
	 * @brief cout the tree sequently
	 * */
	void ShowTree() const;
	/*
	 * @brief allocate the memory
	 * @size memory size(uint:byte)
	 * @return the starting allocated memory address
	 * */
	void *Alloc(unsigned size);
	/*
	 * @brief free the memory
	 * @ptr pointer to the starting memory address 
	 * */
	void Free(void *ptr);
};
}
#endif

/****************************************************************************
@File Name: buddysystem.cpp
@Author: wangzhicheng
@mail: 2363702560@qq.com
@Created Time: Wed 15 Feb 2017 01:54:36 PM CST
			   2017-02-17
****************************************************************************/
#include "buddysystem.h"
namespace buddysystem
{
/*
 * @brief initialize the buddy system
 * @cap the memory capacity unit:Byte
 * @return true if init ok
 * */
bool BuddySystem::Init(unsigned cap)
{
	// check the cap
	if(!PublicUtility::ToPower(cap)) 
	{
		cap = PublicUtility::FixToPower(cap);
	}
	if(cap >= PublicUtility::GetFreeRam()) return false;
	m_nCapacity = cap;
	m_pBasePtr = malloc(m_nCapacity);
	if(!m_pBasePtr) return false;
	unsigned n = (m_nCapacity << 1) - 1;		// n is the count of nodes in the full tree
	int parent;
	m_vecTree.resize(n);
	// fill the tree
	m_vecTree[0] = m_nCapacity;
	for(int i = 1;i < n;i++)
	{
		parent = Parent(i);
		m_vecTree[i] = m_vecTree[parent] >> 1;
	}

	return true;
}
/*
 * @brief cout the tree sequently
 * */
void BuddySystem::ShowTree() const
{
	for_each(begin(m_vecTree), end(m_vecTree), [](unsigned size)
	{
		cout << size << endl;
	});
}
/*
 * @brief allocate the memory
 * @size memory size(uint:byte)
 * @return the starting allocated memory address
 * */
void *BuddySystem::Alloc(unsigned size)
{
	if(!m_pBasePtr) return 0;
	int index = 0;
	unsigned node_size;
	unsigned offset;
	size = PublicUtility::FixToPower(size);
	// lock lockguard
	lock_guard<mutex>lockguard(m_gmutex); 
	// search the fit memory block
	if(m_vecTree[0] < size) return 0;
	for(node_size = m_nCapacity;node_size != size;node_size >>= 1)
	{
		if(m_vecTree[Lchild(index)] >= size) 
		{
			index = Lchild(index);
		}
		else
		{
			index = Rchild(index);
		}
	}
	m_vecTree[index] = 0;
	offset = (index + 1) * node_size - m_nCapacity;
	// adjust the tree
	while(index)
	{
		index = Parent(index);
		m_vecTree[index] = max(m_vecTree[Lchild(index)], m_vecTree[Rchild(index)]);
	}

	return (void *)((char *)m_pBasePtr + offset);
}
/*
 * @brief free the memory
 * @ptr pointer to the starting memory address 
 * */
void BuddySystem::Free(void *ptr)
{
	int index;
	unsigned node_size = 1;
	unsigned offset;
	unsigned lsize;
	unsigned rsize;
	if(!m_pBasePtr) return;
	offset = (char *)ptr - (char *)m_pBasePtr;			// get the offset	pointer to the memory buffer position
	if(offset >= m_nCapacity) throw FreeException();	// check the offset
	index = offset + m_nCapacity - 1;					// get the index pointer to the tree position
	// lock
	lock_guard<mutex>lockguard(m_gmutex); 
	for(;m_vecTree[index];index = Parent(index)) 
	{
		node_size <<= 1;
		if(!index) return;
	}
	m_vecTree[index] = node_size;
	// update parent nodes
	while(index) 
	{
		index = Parent(index);
		node_size <<= 1;
		lsize = m_vecTree[Lchild(index)];
		rsize = m_vecTree[Rchild(index)];
		if(lsize + rsize == node_size) 
		{
 			m_vecTree[index] = node_size;
		}
		else
		{
 			m_vecTree[index] = max(lsize, rsize);
		}
	}
}
}

/****************************************************************************
@File Name: test.cpp
@Author: wangzhicheng
@mail: 2363702560@qq.com
@Created Time: Sat 28 Jan 2017 09:25:55 PM CST
@Revision Time:2017-02-17
****************************************************************************/
#include "buddysystem.h"
#include <thread>
using namespace buddysystem;
void fun0(BuddySystem &bs)
{
	int *p = (int *)bs.Alloc(sizeof(int));
	if(p) 
	{
		*p = 18;
		cout << *p << endl;
		bs.Free(p);
	}
}
void fun1(BuddySystem &bs)
{
	char *ptr = (char *)bs.Alloc(256);
	if(ptr)
	{
		strcpy(ptr, "hello world...!\n");
		cout << ptr << endl;
		bs.Free(ptr);
	}
}
int main()
{
	BuddySystem bs;
	cout << bs.Init(1024) << endl;
	/*
	int *p = (int *)bs.Alloc(sizeof(int));
	if(p) 
	{
		*p = 18;
		cout << *p << endl;
	}
	char *ptr = (char *)bs.Alloc(256);
	if(ptr)
	{
		strcpy(ptr, "hello world...!\n");
		cout << ptr << endl;
	}
*/
	thread t0(fun0, ref(bs));
	thread t1(fun1, ref(bs));
	t0.join();
	t1.join();

	return 0;
}
CC=g++
all:
	$(CC) -std=c++11 -g -o test test.cpp PublicUtility.h PublicUtility.cpp buddysystem.cpp buddysystem.h

假设系统的可利用空间容量为2m个字,则系统开始运行时,整个内存区是一个大小为2m的空闲分区。在系统运行过程中,由于不断的划分,可能会形成若干个不连续的空闲分区,将这些空闲分区根据分区的大小进行分类,对于每一类具有相同大小的所有空闲分区,单独设立一个空闲分区双向链表。这样,不同大小的空闲分区形成了k(0≤k≤m)个空闲分区链表。 当需要为进程分配一个长度为n的存储空间时,首先计算一个i值,使2i-1<n≤2i,然后在空闲分区大小为2i的空闲分区链表中查找。若找到,即把该空闲分区分配给进程。否则,表明长度为2i的空闲分区已经耗尽,则在分区大小为2i+1的空闲分区链表中寻找。若存在2i+1的一个空闲分区,则把该空闲分区分为相等的连个分区,这两个分区称为一对伙伴,其中的一个分区用于分配,而把另一个加入分区大小为2i的空闲分区链表中。若大小为2i+1的空闲分区不存在,则需要查找大小为2i+2的空闲分区,若找到则对其进行两次分割:第一次,将其分割为大小为2i+1的两个分区,一个用于分配,一个加入到大小为2i+1空闲分区链表中;第二次,将第一次用于分配的空闲分区分割为2i的两个分区,一个用于分配,一个加入到大小为2i空闲分区链表中。若仍然找不到,则继续查找大小为2i+3的空闲分区,以此类推。由此可见,在最坏的情况下,可能需要对2k的空闲分区进行k次分割才能得到所需分区。 与一次分配可能要进行多次分割一样,一次回收也可能要进行多次合并,如回收大小为2i的空闲分区时,若事先已存在2i的空闲分区时,则应将其与伙伴分区合并为大小为2i+1的空闲分区,若事先已存在2i+1的空闲分区时,又应继续与其伙伴分区合并为大小为2i+2的空闲分区,依此类推。 2.2 伙伴系统的需求 根据伙伴系统算法的思想,我们组对本系统的功能划分为3种: ⑴ 根据伙伴系统算法分配内存 ⑵ 根据伙伴系统算法回收内存 ⑶ 实时查看内存使用的情况
以下是一个简单的Buddy System的C语言代码实现,用于分配和释放内存块: ```c #include <stdio.h> #include <stdlib.h> #include <math.h> #define MAX_LEVEL 10 // 最大层数 #define MIN_SIZE 8 // 最小内存块大小 // 内存块结构体 typedef struct buddy_block { int level; // 当前层数 int is_free; // 是否空闲 struct buddy_block *next; // 下一个内存块 } buddy_block; // 内存池结构体 typedef struct buddy_pool { int size; // 内存池大小 int max_level; // 最大层数 buddy_block *blocks; // 内存块数组 } buddy_pool; // 初始化内存池 void init_buddy_pool(buddy_pool *pool, int size) { int i, block_size; pool->size = size; pool->max_level = log2(size) - log2(MIN_SIZE) + 1; pool->blocks = (buddy_block *) malloc(sizeof(buddy_block) * size); for (i = 0; i < size; i++) { pool->blocks[i].level = -1; pool->blocks[i].is_free = 1; pool->blocks[i].next = NULL; } // 初始化每个层级的内存块 for (i = 0; i < pool->max_level; i++) { block_size = pow(2, i + log2(MIN_SIZE)); pool->blocks[size / block_size].level = i; pool->blocks[size / block_size].is_free = 1; pool->blocks[size / block_size].next = NULL; } } // 分配内存块 void *buddy_alloc(buddy_pool *pool, int size) { int i, level = ceil(log2(size)) - log2(MIN_SIZE); if (level >= pool->max_level) { return NULL; } // 在当前及以上层级查找空闲块 for (i = level; i <= pool->max_level; i++) { if (pool->blocks[pool->size / pow(2, i)].is_free == 1) { break; } } // 没有找到空闲块 if (i > pool->max_level) { return NULL; } else { // 分裂块 while (i > level) { buddy_block *block = &pool->blocks[pool->size / pow(2, i)]; block->is_free = 0; // 将块分裂为左右两块 block->next = &pool->blocks[pool->size / pow(2, i - 1)]; i--; } buddy_block *block = &pool->blocks[pool->size / pow(2, level)]; block->is_free = 0; return (void *) block; } } // 释放内存块 void buddy_free(buddy_pool *pool, void *ptr) { buddy_block *block = (buddy_block *) ptr; block->is_free = 1; // 合并块 while (block->level < pool->max_level) { buddy_block *buddy = block->next; if (buddy->is_free == 0 || buddy->level != block->level) { break; } // 合并块 block->next = buddy->next; block = &pool->blocks[pool->size / pow(2, block->level + 1)]; block->level = buddy->level + 1; } } // 打印内存池状态 void print_buddy_pool(buddy_pool *pool) { int i, level = -1; for (i = 0; i < pool->size; i++) { if (pool->blocks[i].level != level) { level = pool->blocks[i].level; printf("\nLevel %d:\n", level); } printf("%d ", pool->blocks[i].is_free); } printf("\n"); } int main() { buddy_pool pool; init_buddy_pool(&pool, 128); void *p1 = buddy_alloc(&pool, 16); void *p2 = buddy_alloc(&pool, 64); void *p3 = buddy_alloc(&pool, 32); print_buddy_pool(&pool); buddy_free(&pool, p2); buddy_free(&pool, p3); print_buddy_pool(&pool); return 0; } ``` 在上面的代码中,我们使用buddy_block结构体表示内存块,其中level表示当前块所在的层数,is_free表示该块是否空闲,next表示该块的下一个块。buddy_pool结构体表示内存池,其中size表示内存池大小,max_level表示最大层数,blocks表示内存块数组。 在初始化内存池时,我们根据内存池大小和最小内存块大小计算出最大层数,然后初始化每个层级的内存块。在分配内存块时,我们根据请求的内存大小计算出所需的层数,然后在当前及以上层级查找空闲块,如果没有找到,则返回NULL;如果找到,则将块分裂为左右两块,直到分裂到所需层数。在释放内存块时,我们将块标记为空闲,并尝试合并块,直到无法再合并为止。在打印内存池状态时,我们根据块的层数将块分组,并打印出每个块的空闲状态。 这是一个简单的Buddy System的C语言实现,具有基本的分配和释放功能。在实际使用时,需要根据具体情况进行调整和优化。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值