public static void Main(string[] args)
MemoryAllocator allocator = new MemoryAllocator(1024);
int h1 = allocator.Allocate(200);
int h2 = allocator.Allocate(300);
int h3 = allocator.Allocate(150);
Console.WriteLine(allocator.IsAllocated(h1));
Console.WriteLine(allocator.IsAllocated(h2));
Console.WriteLine(allocator.IsAllocated(h3));
MemoryAllocatorTests tests = new MemoryAllocatorTests();
RunTest(() => tests.Allocate_ValidSize_ReturnsValidHandle(), "Allocate_ValidSize_ReturnsValidHandle");
RunTest(() => tests.Allocate_InsufficientMemory_ReturnsNegativeOne(), "Allocate_InsufficientMemory_ReturnsNegativeOne");
RunTest(() => tests.Allocate_ZeroSize_ThrowsArgumentException(), "Allocate_ZeroSize_ThrowsArgumentException");
RunTest(() => tests.Free_ValidHandle_FreesMemory(), "Free_ValidHandle_FreesMemory");
RunTest(() => tests.Free_InvalidHandle_DoesNotThrowException(), "Free_InvalidHandle_DoesNotThrowException");
RunTest(() => tests.Free_DoubleFree_DoesNotThrowExceptionAndPreventDoubleFree(), "Free_DoubleFree_DoesNotThrowExceptionAndPreventDoubleFree");
RunTest(() => tests.Defragment_BasicDefragmentation_CompactsMemory(), "Defragment_BasicDefragmentation_CompactsMemory");
RunTest(() => tests.IsAllocated_ValidHandle_ReturnsTrueIfAllocated(), "IsAllocated_ValidHandle_ReturnsTrueIfAllocated");
RunTest(() => tests.IsAllocated_ValidHandle_ReturnsFalseIfFreed(), "IsAllocated_ValidHandle_ReturnsFalseIfFreed");
RunTest(() => tests.IsAllocated_InvalidHandle_ReturnsFalse(), "IsAllocated_InvalidHandle_ReturnsFalse");
RunTest(() => tests.MemoryAllocator_ZeroSize_ThrowsArgumentException(), "MemoryAllocator_ZeroSize_ThrowsArgumentException");
RunTest(() => tests.Allocate_ReuseFreedMemory_AllocatesInPreviousFreeBlock(), "Allocate_ReuseFreedMemory_AllocatesInPreviousFreeBlock");
RunTest(() => tests.ThreadSafetyTest(), "ThreadSafetyTest");
Console.WriteLine("all tests executed");
static void RunTest(Action testMethod, string testName)
Console.WriteLine($"✅ {testName} passed");
Console.WriteLine($"❌ {testName} failed: {ex.Message}");
public class MemoryAllocator
private FreeBlock freeListHead;
private object lockObject = new object();
public FreeBlock(int start, int size)
public MemoryAllocator(int size)
throw new ArgumentException("Size must be positive.");
freeListHead = new FreeBlock(0, size);
public int Allocate(int size)
throw new ArgumentException("Size must be positive.");
FreeBlock current = freeListHead;
FreeBlock previous = null;
if (current.size >= size)
int handle = current.start;
if (current.size == size)
freeListHead = current.next;
previous.next = current.next;
public void Free(int handle)
if (handle < 0 || handle >= memorySize)
if (!IsAllocated(handle))
FreeBlock newBlock = new FreeBlock(handle, FindAllocatedBlockSize(handle));
FreeBlock current = freeListHead;
FreeBlock previous = null;
while (current != null && current.start < handle)
newBlock.next = freeListHead;
previous.next = newBlock;
private int FindAllocatedBlockSize(int handle)
FreeBlock current = freeListHead;
if (current.start == handle)
for (int i = handle; i < memorySize; i++)
FreeBlock currentBlock = freeListHead;
while (currentBlock != null)
if (currentBlock.start == i)
currentBlock = currentBlock.next;
private void CoalesceFreeBlocks()
FreeBlock current = freeListHead;
while (current != null && current.next != null)
if (current.start + current.size == current.next.start)
current.size += current.next.size;
current.next = current.next.next;
byte[] tempMemory = new byte[memorySize];
while (originalOffset < memorySize)
FreeBlock currentBlock = freeListHead;
while (currentBlock != null)
if (currentBlock.start == originalOffset)
currentBlock = currentBlock.next;
int blockSize = FindAllocatedBlockSize(originalOffset);
Array.Copy(memory, originalOffset, tempMemory, currentOffset, blockSize);
currentOffset += blockSize;
originalOffset += blockSize;
Array.Copy(tempMemory, memory, memorySize);
freeListHead = new FreeBlock(currentOffset, memorySize - currentOffset);
public bool IsAllocated(int handle)
if (handle < 0 || handle >= memorySize)
FreeBlock current = freeListHead;
if (current.start == handle)
if (current != null && handle >= current.start && handle < current.start + current.size)
if (handle >= current.start && handle < current.start + current.size)
return FindAllocatedBlockSize(handle) > 0;
public class MemoryAllocatorTests
public void Allocate_ValidSize_ReturnsValidHandle()
MemoryAllocator allocator = new MemoryAllocator(1024);
int handle = allocator.Allocate(200);
Assert.That(handle, Is.GreaterThanOrEqualTo(0));
public void Allocate_InsufficientMemory_ReturnsNegativeOne()
MemoryAllocator allocator = new MemoryAllocator(1024);
int handle1 = allocator.Allocate(1024);
int handle2 = allocator.Allocate(1);
Assert.That(handle2, Is.EqualTo(-1));
public void Allocate_ZeroSize_ThrowsArgumentException()
MemoryAllocator allocator = new MemoryAllocator(1024);
Assert.Throws<ArgumentException>(() => allocator.Allocate(0));
public void Free_ValidHandle_FreesMemory()
MemoryAllocator allocator = new MemoryAllocator(1024);
int handle = allocator.Allocate(200);
Assert.That(allocator.IsAllocated(handle), Is.False);
public void Free_InvalidHandle_DoesNotThrowException()
MemoryAllocator allocator = new MemoryAllocator(1024);
Assert.DoesNotThrow(() => allocator.Free(-1));
Assert.DoesNotThrow(() => allocator.Free(2048));
public void Free_DoubleFree_DoesNotThrowExceptionAndPreventDoubleFree()
MemoryAllocator allocator = new MemoryAllocator(1024);
int handle = allocator.Allocate(200);
Assert.DoesNotThrow(() => allocator.Free(handle));
Assert.That(allocator.IsAllocated(handle), Is.False);
public void Defragment_BasicDefragmentation_CompactsMemory()
MemoryAllocator allocator = new MemoryAllocator(1024);
int h1 = allocator.Allocate(200);
int h2 = allocator.Allocate(300);
int h3 = allocator.Allocate(150);
Assert.That(allocator.IsAllocated(h1), Is.False);
Assert.That(allocator.IsAllocated(h2), Is.True);
Assert.That(allocator.IsAllocated(h3), Is.True);
public void IsAllocated_ValidHandle_ReturnsTrueIfAllocated()
MemoryAllocator allocator = new MemoryAllocator(1024);
int handle = allocator.Allocate(200);
Assert.That(allocator.IsAllocated(handle), Is.True);
public void IsAllocated_ValidHandle_ReturnsFalseIfFreed()
MemoryAllocator allocator = new MemoryAllocator(1024);
int handle = allocator.Allocate(200);
Assert.That(allocator.IsAllocated(handle), Is.False);
public void IsAllocated_InvalidHandle_ReturnsFalse()
MemoryAllocator allocator = new MemoryAllocator(1024);
Assert.That(allocator.IsAllocated(-1), Is.False);
Assert.That(allocator.IsAllocated(2048), Is.False);
public void MemoryAllocator_ZeroSize_ThrowsArgumentException()
Assert.Throws<ArgumentException>(() => new MemoryAllocator(0));
public void Allocate_ReuseFreedMemory_AllocatesInPreviousFreeBlock()
MemoryAllocator allocator = new MemoryAllocator(1024);
int h1 = allocator.Allocate(200);
int h2 = allocator.Allocate(100);
Assert.That(h2, Is.EqualTo(h1));
Assert.That(allocator.IsAllocated(h2), Is.True);
public void ThreadSafetyTest()
const int numThreads = 10;
const int numAllocations = 100;
MemoryAllocator allocator = new MemoryAllocator(1024 * 1024);
Thread[] threads = new Thread[numThreads];
for (int i = 0; i < numThreads; i++)
threads[i] = new Thread(() =>
for (int j = 0; j < numAllocations; j++)
int size = new Random().Next(100, 500);
int handle = allocator.Allocate(size);
Thread.Sleep(new Random().Next(1, 10));
Console.WriteLine("Allocation failed");
foreach (var thread in threads)
foreach (var thread in threads)
Console.WriteLine("Thread safety test completed.");