Prerequisite – Buddy System
Question: Write a program to implement the buddy system of memory allocation in Operating Systems.
Explanation –
The buddy system is implemented as follows- A list of free nodes, of all the different possible powers of 2, is maintained at all times (So if total memory size is 1 MB, we’d have 20 free lists to track-one for blocks of size 1 byte, 1 for 2 bytes, next for 4 bytes and so on).
When a request for allocation comes, we look for the smallest block bigger than it. If such a block is found on the free list, the allocation is done (say, the request is of 27 KB and the free list tracking 32 KB blocks has at least one element in it), else we traverse the free list upwards till we find a big enough block. Then we keep splitting it in two blocks-one for adding to the next free list (of smaller size), one to traverse down the tree till we reach the target and return the requested memory block to the user. If no such allocation is possible, we simply return null.
Example:
Let us see how the algorithm proceeds by tracking a memory block of size 128 KB. Initially, the free list is: {}, {}, {}, {}, {}, {}, {}, { (0, 127) }
- Request: 32 bytes
No such block found, so we traverse up and split the 0-127 block into 0-63, 64-127; we add 64-127 to list tracking 64 byte blocks and pass 0-63 downwards; again it is split into 0-31 and 32-63; since we have found the required block size, we add 32-63 to list tracking 32 byte blocks and return 0-31 to user.
List is: {}, {}, {}, {}, {}, { (32, 63) }, { (64, 127) }, {} - Request: 7 bytes
No such block found-split block 32-63 into two blocks, namely 32-47 and 48-63; then split 32-47 into 32-39 and 40-47; finally, return 32-39 to user (internal fragmentation of 1 byte occurs)
List is: {}, {}, {}, { (40, 47) }, { (48, 63) }, {}, { (64, 127) }, {} - Request: 64 bytes
Straight up memory segment 64-127 will be allocated as it already exists.
List is: {}, {}, {}, { (40, 47) }, { (48, 63) }, {}, {}, {} - Request: 56 bytes
Result: Not allocated
The result will be as follows:

Figure – Buddy Allocation-128 shows the starting address of next possible block (if main memory size ever increases)
Implementation –
C++
#include<bits/stdc++.h>
using namespace std;
int size;
vector<pair< int , int >> free_list[100000];
map< int , int > mp;
void initialize( int sz)
{
int n = ceil ( log (sz) / log (2));
size = n + 1;
for ( int i = 0; i <= n; i++)
free_list[i].clear();
free_list[n].push_back(make_pair(0, sz - 1));
}
void allocate( int sz)
{
int n = ceil ( log (sz) / log (2));
if (free_list[n].size() > 0)
{
pair< int , int > temp = free_list[n][0];
free_list[n].erase(free_list[n].begin());
cout << "Memory from " << temp.first
<< " to " << temp.second << " allocated"
<< "\n" ;
mp[temp.first] = temp.second -
temp.first + 1;
}
else
{
int i;
for (i = n + 1; i < size; i++)
{
if (free_list[i].size() != 0)
break ;
}
if (i == size)
{
cout << "Sorry, failed to allocate memory \n" ;
}
else
{
pair< int , int > temp;
temp = free_list[i][0];
free_list[i].erase(free_list[i].begin());
i--;
for (; i >= n; i--)
{
pair< int , int > pair1, pair2;
pair1 = make_pair(temp.first,
temp.first +
(temp.second -
temp.first) / 2);
pair2 = make_pair(temp.first +
(temp.second -
temp.first + 1) / 2,
temp.second);
free_list[i].push_back(pair1);
free_list[i].push_back(pair2);
temp = free_list[i][0];
free_list[i].erase(free_list[i].begin());
}
cout << "Memory from " << temp.first
<< " to " << temp.second
<< " allocated" << "\n" ;
mp[temp.first] = temp.second -
temp.first + 1;
}
}
}
int main()
{
initialize(128);
allocate(32);
allocate(7);
allocate(64);
allocate(56);
return 0;
}
|
Java
import java.io.*;
import java.util.*;
class Buddy {
class Pair
{
int lb, ub;
Pair( int a, int b)
{
lb = a;
ub = b;
}
}
int size;
ArrayList<Pair> arr[];
@SuppressWarnings ( "unchecked" )
Buddy( int s)
{
size = s;
int x = ( int )Math.ceil(Math.log(s) / Math.log( 2 ));
arr = new ArrayList[x + 1 ];
for ( int i = 0 ; i <= x; i++)
arr[i] = new ArrayList<>();
arr[x].add( new Pair( 0 , size - 1 ));
}
void allocate( int s)
{
int x = ( int )Math.ceil(Math.log(s) / Math.log( 2 ));
int i;
Pair temp = null ;
if (arr[x].size() > 0 )
{
temp = (Pair)arr[x].remove( 0 );
System.out.println( "Memory from " + temp.lb
+ " to " + temp.ub + " allocated" );
return ;
}
for (i = x + 1 ; i < arr.length; i++) {
if (arr[i].size() == 0 )
continue ;
break ;
}
if (i == arr.length)
{
System.out.println( "Sorry, failed to allocate memory" );
return ;
}
temp = (Pair)arr[i].remove( 0 );
i--;
for (; i >= x; i--) {
Pair newPair = new Pair(temp.lb, temp.lb
+ (temp.ub - temp.lb) / 2 );
Pair newPair2 = new Pair(temp.lb
+ (temp.ub - temp.lb + 1 ) / 2 , temp.ub);
arr[i].add(newPair);
arr[i].add(newPair2);
temp = (Pair)arr[i].remove( 0 );
}
System.out.println( "Memory from " + temp.lb
+ " to " + temp.ub + " allocated" );
}
public static void main(String args[]) throws IOException
{
int initialMemory = 0 , val = 0 ;
initialMemory = 128 ;
Buddy obj = new Buddy(initialMemory);
obj.allocate( 32 );
obj.allocate( 7 );
obj.allocate( 64 );
obj.allocate( 56 );
}
}
|
C#
using System;
using System.Collections.Generic;
public class Buddy
{
class Pair
{
public int lb, ub;
public Pair( int a, int b)
{
lb = a;
ub = b;
}
}
int size;
List<Pair> []arr;
Buddy( int s)
{
size = s;
int x = ( int )Math.Ceiling(Math.Log(s) /
Math.Log(2));
arr = new List<Pair>[x + 1];
for ( int i = 0; i <= x; i++)
arr[i] = new List<Pair>();
arr[x].Add( new Pair(0, size - 1));
}
void allocate( int s)
{
int x = ( int )Math.Ceiling(Math.Log(s) /
Math.Log(2));
int i;
Pair temp = null ;
if (arr[x].Count > 0)
{
temp = (Pair)arr[x][0];
arr[x].RemoveAt(0);
Console.WriteLine( "Memory from " + temp.lb +
" to " + temp.ub + " allocated" );
return ;
}
for (i = x + 1; i < arr.Length; i++)
{
if (arr[i].Count == 0)
continue ;
break ;
}
if (i == arr.Length)
{
Console.WriteLine( "Sorry, failed to" +
" allocate memory" );
return ;
}
temp = (Pair)arr[i][0];
arr[i].RemoveAt(0);
i--;
for (; i >= x; i--)
{
Pair newPair = new Pair(temp.lb, temp.lb +
(temp.ub - temp.lb) / 2);
Pair newPair2 = new Pair(temp.lb + (temp.ub -
temp.lb + 1) / 2, temp.ub);
arr[i].Add(newPair);
arr[i].Add(newPair2);
temp = (Pair)arr[i][0];
arr[i].RemoveAt(0);
}
Console.WriteLine( "Memory from " + temp.lb +
" to " + temp.ub + " allocated" );
}
public static void Main(String []args)
{
int initialMemory = 0;
initialMemory = 128;
Buddy obj = new Buddy(initialMemory);
obj.allocate(32);
obj.allocate(7);
obj.allocate(64);
obj.allocate(56);
}
}
|
Javascript
<script>
class Pair
{
constructor(a, b)
{
this .lb = a;
this .ub = b;
}
}
let size;
let arr;
function Buddy(s)
{
size = s;
let x = Math.ceil(Math.log(s) / Math.log(2));
arr = new Array(x + 1);
for (let i = 0; i <= x; i++)
arr[i] =[];
arr[x].push( new Pair(0, size - 1));
}
function allocate(s)
{
let x = Math.floor(Math.ceil(
Math.log(s) / Math.log(2)));
let i;
let temp = null ;
if (arr[x].length > 0)
{
temp = arr[x].shift();
document.write( "Memory from " + temp.lb +
" to " + temp.ub + " allocated<br>" );
return ;
}
for (i = x + 1; i < arr.length; i++)
{
if (arr[i].length == 0)
continue ;
break ;
}
if (i == arr.length)
{
document.write( "Sorry, failed to " +
"allocate memory<br>" );
return ;
}
temp = arr[i].shift(0);
i--;
for (; i >= x; i--)
{
let newPair = new Pair(temp.lb,
temp.lb +
Math.floor(
(temp.ub -
temp.lb) / 2));
let newPair2 = new Pair(temp.lb +
Math.floor(
(temp.ub -
temp.lb + 1) / 2),
temp.ub);
arr[i].push(newPair);
arr[i].push(newPair2);
temp = arr[i].shift(0);
}
document.write( "Memory from " + temp.lb +
" to " + temp.ub + " allocated<br>" );
}
let initialMemory = 0, val = 0;
initialMemory = 128;
Buddy(initialMemory);
allocate(32);
allocate(7);
allocate(64);
allocate(56);
</script>
|
Output: Memory from 0 to 31 allocated
Memory from 32 to 39 allocated
Memory from 64 to 127 allocated
Sorry, failed to allocate memory
Time Complexity –
If the main memory size is n, we have log(n) number of different powers of 2 and hence log(n) elements in the array (named arr in the code) tracking free lists. To allocate a block, we only need to traverse the array once upwards and once downwards, hence time complexity is O(2log(n)) or simply O(logn)