Up to this point the sizes of blocks have been either fixed or completely arbitrary. Another

technique used in some storage methods is to restrict the sizes of  blocks to some fixed set

of sizes. All the blocks of each size can be linked together with the intent of speeding up the

search for a block of suitable size. For a request of a block of size n, the number m, the sm-

allest of the fixed sizes equal to or larger than n, is determined and a block of size m is all-

ocated . If no block of size m is available, then a larger block is split into two sub blocks

(known as buddies), each also of fixed size, and this process is repeated until a block of size

m is produced.

 

Besides the improvement in search time, there is another advantage in using in using

this technique. The collapsing of two smaller blocks into one larger block is relatively easy

since only two buddies formed by splitting a larger block may be combined to form this lar-

ger block once again. Because the sizes are fixed relative to one another, the address of the

buddy of a block is relatively easily determined.

         There are, however, some potential disadvantages associated with this technique. Inter-

nal fragmentation will be increased generally because of the allocation of blocks which may

be somewhat larger than the requested size. As well, there can be an increased amount of ex-

ternal fragmentation due to the fact that two blocks may be contiguous and yet not merged,

because they are not buddies. Generally, though, this technique of storage management has

proven to be quite efficient.

The usual approach in implementing this method of storage management is to specify

the fixed sizes, F0, Fl, …., F max, for blocks according to some pattern such as the recurrence

relation.

          Fn =Fn-1 +Fn-k   k<=n<=MAX

          F0 = a, Fl=b, ….,  Fk-1=c

          where  a ,b,….,c are minimum block sizes that are used , and k=1 or 2 or 3 or….etc. For

example, if k is one and F0 is 1, then the block sizes, which are 1,2,4,8,16, …, are the successive

powers of 2 and the method is called the buddy system. If  k=2 with F0=F1=1, then the sizes are

just the successive members of the Fibonacci sequence 1,1,2,3,5,8,13,…In all likelihood, though,

though, the F0,F1,etc.., terms are not defined to be such small values. Blocks of size 1are not much

use, especially if they must carry control information so that the allocation and release mechanisms

will work.

          The feature that makes this system work is that the merges must correspond exactly to the splits.

By this we mean that the only two blocks that can be merged are the precise two that were formed by

splitting. Furthermore, before each block can be reformed, each of its sub blocks must be reformed

from their sub blocks. Consequently, the storage-block pattern formed by the sequence of splits has the

form of a binary tree. The problem with which we are faced is the recording of the position of a parti-

cular block within this tree structure.

          One particular solution consists of a coding for each block by which we can reconstruct splitting

sequence that produced that block. Looking at the recurrence relation Fn = Fn-1+ Fn-k, if we specify

that the Fn-1 term corresponds to the block that forms the left branch of a split and the Fn-k term is

the right branch, then all we must record for each block is the size of the block, the number of splits

it took to form the block, and whether it is a left block or right block. Since one left block and one

right block are formed in each split, we need only record the count of left blocks. In fact, this allows

us to code the left or right factor together with the split count in one coded field. The left block has the

relative split count, while the right block has a code of 0. The formulas to use are the following:

           Initially: CODEmax= 0 where Fmax is the entire segment considered to be a right block

Splitting: CODEleft= CODEparent +1

                 CODEright=0

Merging: CODEparent= CODEleft +1

 

1

 
 

      

 

 

 

 

 

 

 

 

 

As an example, consider a storage block of 144 cells and the recurrence relation

Fn=Fn-1+Fn-2    2≤n≤6

F0=8, F1=13

 

The entire tree of possible splits is given in the figure where the vertex value is the block size and the

superscript is the code value as computed by the above formulas. Consider the tree cross section that is

the set of potential blocks of size 13. A block of size 13 with code of 0 is the right block formed by

splitting a block of size 34. The left or right nature of this size 34 block is determined by the left buddy

for the block of size 13. If its left buddy has a code of 1, then the size 34 block is the right block for

some larger block of size 89, while if the left buddy has a code greater than 1, then the block of size 34

is a left block of some still larger block. A block of size 13 with a code value greater than 0 is the left

block of a split block of size 31. The numeric value of the code for a left block of size 13 is the

number of splits of some higher right block that had to be made to get this left block of size 13. Or, in

other words, the value of the code for a left block is the number of merges that this left block must

under go to become the first 13 locations of some larger block which is finally a right block.

 

 FREE(P) is 0 or greater than 0, depending on whether block P is free, SIZE(P) contains the value I for

block P of size Fi, SUC(P) and PRED(P) for a free block P are the forward and backward pointers to

other free blocks of size Fi in a doubly linked list of all the free blocks of size Fi. The list head with

address AVAIL[i] for this list if given in the figure. CODE(P) for block P is the code giving the left or

right handedness of block P and the relative split count if P is a left block. In addition to the array of

list heads AVAIL[0:MAX], we also have the array F[0:MAX], which records the block sizes Fi,

0<=i<=MAX, as determined by the recurrence relation. It is assumed that F0 has a value large enough

to allot the storage of the control fields.

 

The following are the 2 sub algorithms that take care of the insertion and deletion of blocks into and

from the above linked lists.

 

Procedure: INSERT(P,I) given the arrays and block structures as previously described, parameters I

and P, this procedure inserts P into the list headed by AVAIL[I].

 

1.FREE(P)←0

 SIZE(P) ←1

 SUC(P) ←SUC(AVAIL[I])

 SUC(AVAIL[I]) ←P

 PRED(P) ←AVAIL[I]

 PRED(SUC(P)) ←P

2.[finished]

      Return

Procedure: DELETE(P). Given the arrays and block structures as previously described and parameter

P, this algorithm deletes block P from the list in which it appears.

1. SUC(PRED(P)) ←SUC(P)

   PRED(SUC(P)) ←PRED(P)

2.[Finished]

       Return

   A general algorithm for allocating storage using the buddy system is as follows:

       1. Check that the requested amount of storage is not larger than amount available.

       2. Determine the smallest size block larger than the requested amount of storage.

       3. Search list head blocks for smallest free block greater than or equal to the

           requested size.

       4. If such a block does not exist then return.

       5. Remove the free block from its linked list.

       6. Repeat step 7 until the correct size is reached.

       7. Split the block into buddies and place inappropriate buddy on its linked list.

       8. Return address of block.

                     The following algorithm services the request for storage blocks.

   The algorithm presumes that the value of K has been fixed so as to determine which

   recurrence relation is being used.

   Function: ALLOCATE_BUDDY(N). Given the arrays and block structures as 

   previously described, this algorithm receives a request for a block of size N and

   returns the pointer P set to the address of block of size Fi , which is the smallest

   size larger than or equal to N. It is assumed that the value of K has been fixed so

   as to determine which recurrence relation is being used. Local variables include I

   and J (integers) and Q(pointer).

1.     [Determine size code]

                   If  N>F[MAX]

                   then   Return(NULL)

                   else    I←0

                             Repeat while N>F[I]

                                      I←I+1

2.     [Find first available block]

J←I

Repeat while SUC(AVAIL[J])=AVAIL[J]

          J←J+1

          If J>MAX

          then   Return(NULL)

P←SUC(AVAIL[J])

Call DELETE(P)

3.     [Split as required until correct size is reached]

          Repeat while J>I and J≥K

                   Q←P+F[J-1]

                   CODE(P) ←CODE(P)+1

                   CODE(Q) ←0

                   If I>J-K

                   then   Call INSERT(Q,J-K)

                             J←SIZE(P) ←J-1

                   else    Call INSERT(P,J-1)

                             J←SIZE(Q) ←J-K

                             P←Q

4.     [Allocate block P of size Fi]

FREE(P) ←1

Return(P)

 

In the First step of the function, a check is made to ensure the requested amount of storage is not larger

that the amount available. If such a condition occurs, a NULL value is returned and appropriate action

is assumed to be taken in the calling program. Otherwise, the first step of the algorithm determines the

smallest size of block that is larger than the requested amount of storage. The second step searches the

list head blocks for the smallest free block equal to or larger than the required size. If such a block is

found, it is removed from the doubly linked list. The third step controls the splitting operation on this

block. The if statement in step 3 causes the left buddy of each split block to be placed on the

appropriate linked list until one of the left buddies satisfies the request size. the inappropriate

buddy(either left or right) is placed on the correct linked list, while the other buddy is marked

allocated and its address returned.

 

 

Consider the following situation. A request for a block of storage of size 30(N =30) has been received.

 The storage allocation system in use us the Fibonacci buddy system described previously(K=2 and

MAX=6). Initially, the entire block of size 144 is free, as shown in Fig. The SUC and PRED fields

have been dropped to simplify the diagram. Since the block of size 144 is the smallest block larger

than size 30, it is selected, Figure shows the first split of this block. The smallest right buddy is again

 split as shown in the figure. The new right buddy is still larger than the requested size, so the larger

left buddy is marked free, and the CODE is set to zero indicating a right buddy and placed on the

appropriate linked list. the left buddy in Figure is the most efficient size for the request. This block is

marked occupied and its address is returned to the calling program. Figure shows the segment of

memory after the splitting is complete. The occupied bock is indicated by shading.

 

The following general algorithm controls the return of storage, merging with appropriate buddies

whenever possible. The algorithm assumes K has been set to indicate the recurrence relation being

used.

 

1.     Repeat step 2 until all possible merges have been made.

2.     If the code of the freed block is greater than zero

then   determine the address of its right buddy

                   if the right buddy is occupied or the wrong size

                   then   insert the free block on the appropriate list and return

                   else    remove the right the buddy from its linked list and combine buddies

else    determine the address of its left buddy

                   if the left buddy is occupied or the wrong size

                   then   insert the free block on the appropriate list and return

                   else    remove the left buddy from its linked list and combine buddies

3.     Insert maximal block on appropriate linked list

 

A detailed algorithm for this function is now presented.

 

Procedure: FREE_BUDDY(P). Given a block beginning at address P, this algorithm inserts it(or merges of it with appropriate buddies) onto the proper free list. It is assumed that the value of K has been fixed so as to determine which recurrence relation is being used. Q is local variable.

 

1.     [Perform all possible merger]

Repeat step 2 while SIZE(P)<MAX

2.     [Merges blocks]

If CODE(P)>0

then   Q←P+F[SIZE{P}]

          (P is a left block, Q is address of right block)

          If FREE(Q)>0 or SIZE(Q)≠SIZE(P)-K+1

          then   (right block id occupied or wrong size)

                   Call INSERT(P,SIZE(P))

                   Return

          else    (combine buddies)

                   CODE(P) ←CODE(P) -1

                   SIZE(P) ←SIZE(P)+1

                   Call DELETE(Q)

else    (P is a right block, Q is address of left block)

          Q←P-F[SIZE(P)+K-1]

          If FREE(Q)>0 or SIZE(Q) ≠ SIZE(P) +K-1

          then   (left block is occupied or wrong size)

                   Call INSERT(P,SIZE(P))

Return

else    (combine buddies)

          CODE(Q) ←CODE(Q)-1

          SIZE(Q) ←SIZE(Q)+1

          Call DELETE(Q)

          P←Q

3.     [We get here if only if P is maximal block]

Call INSERT(P,MAX)

Return

 

The first step of the algorithm controls the merging process. The second step performs the actual

merging  of blocks. If the CODE of freed block is greater than 0, P is a left block; otherwise it is a

right block. In both these cases, if the neighboring block to the retuned block is free and a buddy, the

two blocks are combined and the looping continues. If the neighboring block is not a buddy or is in

use, the function places the final block on the appropriate linked list and terminates.

 

Suppose that the previously allocated block of storage in Figure is now released. The initial situation is

given in the Figure. The PRED and SUC fields have once more been let out to simplify the diagram.

 

 

Since the CODE of the released block is greater than 0, it is recognized as a left block. Its right buddy

 is examined and found to be free, allowing the two blocks to be merged. CODE field of the new block

 is determined and its SIZE field incremented. The situation after this process is shown in the Figure.

The CODE field of this new block is 0, indicating a right block. The left buddy of this block is free,

and the two blocks are combined following the same procedure as described above. Since P is now the

maximal block, it is inserted on the appropriate linked list and the function terminates. The final result

is shown in the figure.

 

It should be noted that when K=1(when the strategy is in effect the buddy system), then the addresses

of buddies differ from each other by amounts that are integral powers of two. Since all addresses are

in binary representation in a computer, the address calculating given earlier could be replaced by a

method that makes use of this fact, possibly speeding up these algorithms.

 

With regard to the performance of the algorithms, Knuth’s simulation showed that the buddy

performed quite well, comparable to his boundary-tag method, and in fact, buddy system has proven

itself in practice. Statistical analysis has been performed on the Fibonacci system, and the results

appear to show it to be superior to the buddy system(quite possibly because of the wider range of

block sizes available for a given segment of storage). The advantage of the Fibonacci system which

makes it appear even more useful is that the average amount of wasted storage is less than for the

buddy system. This is because there are at least as many Fibonacci numbers less than a given number

than there are integral powers of two. In fact, for n>4, there are always more Fibonacci numbers less

than or equal to n than there are powers of two, while n≤4, there are at least as any Fibonacci numbers.

Hence the Fibonacci system has more sizes available and is more likely to achieve a better fit of

allocated amount to requested amount. In summary, then, both of these methods appear to be suitable

for use as part of a storage management system.