最近项目上涉及内存管理,继而了解了伙伴系统,发现很有意思,于是实现了一版简单的,效率和参数校验上都没有太理会,仅仅正向测试了下,分享给大家,Github完整源码见如下链接(源码有注释图,更加清晰):
简易版buddySystem
手机版复制地址打开:https://github.com/CallonHuang/BuddySystem
两个核心的函数如下:
int BuddyAlloc(BUDDY_TYPE buddy_type, void **viraddr)
{
int i = 0;
BUDDY_INFO* target_node;
if (free_area[buddy_type].list.count != 0)
{
target_node = (BUDDY_INFO *)free_area[buddy_type].list.node.next;
*viraddr = target_node->start;
ListDelete(&free_area[buddy_type].list, (NODE *)target_node);
free(target_node);
}
else
{
for (i = buddy_type; i < BUDDY_TYPE_MAX; i++)
{
if (free_area[i].list.count != 0)
{
break;
}
}
if (i != BUDDY_TYPE_MAX)
{
SplitNode(buddy_type, i);
return BuddyAlloc(buddy_type, viraddr);
}
else
{
return -1;
}
}
return 0;
}
void BuddyRecycle(BUDDY_TYPE buddy_type, void *viraddr)
{
int i = 0, bMerged = 0;
BUDDY_INFO* cur_node = NULL;
BUDDY_INFO* target_node = (BUDDY_INFO *)malloc (sizeof(BUDDY_INFO));
target_node->start = viraddr;
for (cur_node = (BUDDY_INFO*)free_area[buddy_type].list.node.next;
cur_node != (BUDDY_INFO*)&free_area[buddy_type].list.node;
cur_node = (BUDDY_INFO*)cur_node->list.node.next)
{
if (cur_node->start > viraddr)
{
break;
}
}
ListInsert(&free_area[buddy_type].list, (NODE *)target_node, (NODE *)cur_node);
for (i = buddy_type; i < BUDDY_TYPE_MAX-1; )
{
if (free_area[i].list.count > 1)
{
for (cur_node = (BUDDY_INFO*)free_area[i].list.node.next;
cur_node->list.node.next != &free_area[i].list.node;
cur_node = (BUDDY_INFO*)cur_node->list.node.next)
{
if (MergeNode(i, cur_node, (BUDDY_INFO*)cur_node->list.node.next) == 0)
{
bMerged = 1;
break;
}
}
}
if (!bMerged)
i++;
else
bMerged = 0;
}
}
分别是分配和回收,从中可以看到伙伴系统的机制:
- 分配:若所需要的内存块链表中没有node,则向上请求更大内存的链表,直到请求到后,逐级分解直至有所需要的内存块,最后分配;
- 回收:找到合适的地方插入(保证节点是地址有序的),然后从该节点所在链表进行遍历,查看能否合并,并且逐级向上查看更大内存中是否存在可以合并的连续内存块,合并又有两个原则:必须连续且到起始的偏移必须是高阶内存的整数倍。