## Buddy system伙伴分配器实现

2014-04-27 16:42  youxin  阅读(3421)  评论(0编辑  收藏  举报

wikipedia：http://en.wikipedia.org/wiki/Buddy_memory_allocation

The buddy memory allocation technique is a memory allocation algorithm that divides memory into partitions to try to satisfy a memory request as suitably as possible. This system makes use of splitting memory into halves to try to give a best-fit. According to Donald Knuth, the buddy system was invented in 1963 byHarry Markowitz, who won the 1990 Nobel Memorial Prize in Economics, and was first described by Kenneth C. Knowlton (published 1965).[1] Buddy memory allocation is relatively easy to implement. It supports limited but efficient splitting and coalescing of memory blocks.

how it works:

There are various forms of the buddy system, but binary buddies, in which each block is subdivided into two smaller blocks, are the simplest and most common variety. Every memory block in this system has an order, where the order is an integer ranging from 0 to a specified upper limit. The size of a block of order n is proportional to 2n, so that the blocks are exactly twice the size of blocks that are one order lower. Power-of-two block sizes make address computation simple, because all buddies are aligned on memory address boundaries that are powers of two. When a larger block is split, it is divided into two smaller blocks, and each smaller block becomes a unique buddy to the other. A split block can only be merged with its unique buddy block, which then reforms the larger block they were split from.

Starting off, the size of the smallest possible block is determined, i.e. the smallest memory block that can be allocated. If no lower limit existed at all (e.g., bit-sized allocations were possible), there would be a lot of memory and computational overhead for the system to keep track of which parts of the memory are allocated and unallocated. However, a rather low limit may be desirable, so that the average memory waste per allocation (concerning allocations that are, in size, not multiples of the smallest block) is minimized. Typically the lower limit would be small enough to minimize the average wasted space per allocation, but large enough to avoid excessive overhead. The smallest block size is then taken as the size of an order-0 block, so that all higher orders are expressed as power-of-two multiples of this size.

The programmer then has to decide on, or to write code to obtain, the highest possible order that can fit in the remaining available memory space. Since the total available memory in a given computer system may not be a power-of-two multiple of the minimum block size, the largest block size may not span the entire memory of the system. For instance, if the system had 2000K of physical memory and the order-0 block size was 4K, the upper limit on the order would be 8, since an order-8 block (256 order-0 blocks, 1024K) is the biggest block that will fit in memory. Consequently it is impossible to allocate the entire physical memory in a single chunk; the remaining 976K of memory would have to be allocated in smaller blocks.

As you can see, what happens when a memory request is made is as follows:

• If memory is to be allocated
1. Look for a memory slot of a suitable size (the minimal 2k block that is larger or equal to that of the requested memory)
1. If it is found, it is allocated to the program
2. If not, it tries to make a suitable memory slot. The system does so by trying the following:
1. Split a free memory slot larger than the requested memory size into half
2. If the lower limit is reached, then allocate that amount of memory
3. Go back to step 1 (look for a memory slot of a suitable size)
4. Repeat this process until a suitable memory slot is found
• If memory is to be freed
1. Free the block of memory
2. Look at the neighboring block - is it free too?
3. If it is, combine the two, and go back to step 2 and repeat this process until either the upper limit is reached (all memory is freed), or until a non-free neighbour block is encountered

1.寻找大小合适的内存块（大于等于所需大小并且最接近2的幂，比如需要27，实际分配32）

1.如果找到了，分配给应用程序。
2.如果没找到，分出合适的内存块。

1.对半分离出高于所需大小的空闲内存块
2.如果分到最低限度，分配这个大小。
3.回溯到步骤1（寻找合适大小的块）
4.重复该步骤直到一个合适的块

1.释放该内存块

1.寻找相邻的块，看其是否释放了。
2.如果相邻块也释放了，合并这两个块，重复上述步骤直到遇上未释放的相邻块，或者达到最高上限（即所有内存都释放了）。

1. 我们发现1024K的一半大于70K，然后我们就把1024K的内存分成两半，一半512K。
2. 然后我们发现512K的一半仍然大于70K，于是我们再把512K的内存再分成两半，一半是128K。
3. 此时，我们发现128K的一半小于70K，于是我们就分配为A分配128K的内存。

 1 2 3 4 struct buddy2 {   unsigned size;   unsigned longest[1]; };

 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 struct buddy2* buddy2_new( int size ) {   struct buddy2* self;   unsigned node_size;   int i;     if (size < 1 || !IS_POWER_OF_2(size))     return NULL;     self = (struct buddy2*)ALLOC( 2 * size * sizeof(unsigned));   self->size = size;   node_size = size * 2;     for (i = 0; i < 2 * size - 1; ++i) {     if (IS_POWER_OF_2(i+1))       node_size /= 2;     self->longest[i] = node_size;   }   return self; }

 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 int buddy2_alloc(struct buddy2* self, int size) {   unsigned index = 0;   unsigned node_size;   unsigned offset = 0;     if (self==NULL)     return -1;     if (size <= 0)     size = 1;   else if (!IS_POWER_OF_2(size))     size = fixsize(size);     if (self->longest[index] < size)     return -1;     for(node_size = self->size; node_size != size; node_size /= 2 ) {     if (self->longest[LEFT_LEAF(index)] >= size)       index = LEFT_LEAF(index);     else       index = RIGHT_LEAF(index);   }     self->longest[index] = 0;   offset = (index + 1) * node_size - self->size;     while (index) {     index = PARENT(index);     self->longest[index] =       MAX(self->longest[LEFT_LEAF(index)], self->longest[RIGHT_LEAF(index)]);   }     return offset; }

 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 void buddy2_free(struct buddy2* self, int offset) {   unsigned node_size, index = 0;   unsigned left_longest, right_longest;     assert(self && offset >= 0 && offset < size);     node_size = 1;   index = offset + self->size - 1;     for (; self->longest[index] ; index = PARENT(index)) {     node_size *= 2;     if (index == 0)       return;   }     self->longest[index] = node_size;     while (index) {     index = PARENT(index);     node_size *= 2;       left_longest = self->longest[LEFT_LEAF(index)];     right_longest = self->longest[RIGHT_LEAF(index)];       if (left_longest + right_longest == node_size)       self->longest[index] = node_size;     else       self->longest[index] = MAX(left_longest, right_longest);   } }