在连续内存分配中,伙伴系统是一种用于管理空闲内存的算法。它将内存划分为一系列的块,每个块的大小是 2 的幂次方,例如 16 字节、32 字节、64 字节等。每个块都有一个伙伴,伙伴是指与该块具有相同大小的另一个块。例如,一个 64 字节的块的伙伴是另一个 64 字节的块。
当需要分配内存时,伙伴系统会查找一个足够大的空闲块来满足请求。如果找到了一个合适的块,它会将该块分配给请求者,并将该块的伙伴标记为已使用。如果没有找到合适的块,则会继续查找更大的块,直到找到为止。
当需要释放内存时,伙伴系统会将释放的块与它的伙伴合并成一个更大的块。如果合并后的块仍然有伙伴,它会继续与伙伴合并,直到没有伙伴为止。这样可以减少内存碎片的产生,提高内存的利用率。
下面是一个简单的 Python 实现示例:
# 定义块的大小
BLOCK_SIZE = 16
# 定义伙伴系统的类
class BuddySystem:
def __init__(self):
self.free_lists = [[] for _ in range(BLOCK_SIZE)]
# 分配内存
def allocate(self, size):
if size == 0:
return 0
index = self.find_index(size)
if index < 0:
return -1
block = self.free_lists[index].pop(0)
block_size = self.block_size(index)
if size < block_size:
self.split_block(index, size)
return block
# 释放内存
def free(self, block):
index = self.find_index(self.block_size(block))
if index < 0:
return
self.free_lists[index].append(block)
# 查找适合的块索引
def find_index(self, size):
for i in range(BLOCK_SIZE - 1, -1, -1):
if size <= self.block_size(i):
return i
return -1
# 获取块的大小
def block_size(self, index):
return 2 ** index
# 分割块
def split_block(self, index, size):
block_size = self.block_size(index)
new_index = index + 1
if size == block_size:
return
new_block = self.allocate(size)
if new_block == -1:
return
self.free_lists[new_index].append(new_block)
# 更新伙伴
self.free_lists[index].append((new_block + size, new_index))
# 创建伙伴系统对象
buddy_system = BuddySystem()
# 分配内存
block1 = buddy_system.allocate(32)
block2 = buddy_system.allocate(64)
# 释放内存
buddy_system.free(block1)
buddy_system.free(block2)
# 分配内存
block3 = buddy_system.allocate(128)
block4 = buddy_system.allocate(256)
# 输出分配的内存地址
print("Block1:", hex(block1))
print("Block2:", hex(block2))
print("Block3:", hex(block3))
print("Block4:", hex(block4))
在这个示例中,我们定义了一个块的大小为 16 字节,并且定义了一个 BuddySystem 类来实现伙伴系统。在 BuddySystem 类中,我们使用一个列表来存储空闲块的地址,列表的索引表示块的大小。在分配内存时,我们根据请求的大小查找适合的块索引,并从空闲列表中弹出一个空闲块。如果请求的大小小于块的大小,我们会将块分割成两个更小的块,并将它们添加到空闲列表中。在释放内存时,我们将释放的块添加到空闲列表中,并将它的伙伴标记为已使用。
在示例中,我们首先创建了一个 BuddySystem 对象,并使用 allocate 方法分配了两个内存块。然后,我们使用 free 方法释放了这两个内存块。最后,我们再次分配了两个内存块,并输出它们的地址。
需要注意的是,这只是一个简单的示例,实际的伙伴系统实现可能会更加复杂,并且需要考虑更多的细节,例如内存对齐、内存回收等。