implement memory freeing and block merging
This commit is contained in:
@@ -15,6 +15,11 @@
|
|||||||
|
|
||||||
#define HEAP_MIN_FREE_BLOCK_SIZE 64 // min. Groesse eines freien Blocks
|
#define HEAP_MIN_FREE_BLOCK_SIZE 64 // min. Groesse eines freien Blocks
|
||||||
|
|
||||||
|
// I don't order the list by size so that the block order corresponds to the location in memory
|
||||||
|
// Then I can easily merge adjacent free blocks by finding the previous block without looking at
|
||||||
|
// memory addresses of each block
|
||||||
|
// (That was the plan at least)
|
||||||
|
|
||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
* Methode: LinkedListAllocator::init *
|
* Methode: LinkedListAllocator::init *
|
||||||
*---------------------------------------------------------------------------*
|
*---------------------------------------------------------------------------*
|
||||||
@@ -30,11 +35,12 @@ void LinkedListAllocator::init() {
|
|||||||
/* Hier muess Code eingefuegt werden */
|
/* Hier muess Code eingefuegt werden */
|
||||||
|
|
||||||
this->free_start = (struct free_block*)this->heap_start;
|
this->free_start = (struct free_block*)this->heap_start;
|
||||||
|
this->free_start->allocated = false;
|
||||||
this->free_start->size = this->heap_size - sizeof(struct free_block);
|
this->free_start->size = this->heap_size - sizeof(struct free_block);
|
||||||
this->free_start->next = this->free_start; // Only one block, points to itself
|
this->free_start->next = this->free_start; // Only one block, points to itself
|
||||||
|
|
||||||
kout << "Initialized LinkedList Allocator" << endl
|
kout << "Initialized LinkedList Allocator" << endl
|
||||||
<< "Heap Start: " << hex << (unsigned int)this->heap_start
|
<< " - Heap Start: " << hex << (unsigned int)this->heap_start
|
||||||
<< ", Heap End: " << hex << (unsigned int)this->heap_end
|
<< ", Heap End: " << hex << (unsigned int)this->heap_end
|
||||||
<< ", Heap Size: " << hex << this->heap_size << endl;
|
<< ", Heap Size: " << hex << this->heap_size << endl;
|
||||||
kout << endl;
|
kout << endl;
|
||||||
@@ -52,9 +58,9 @@ void LinkedListAllocator::dump_free_memory() {
|
|||||||
kout << "Freier Speicher:" << endl;
|
kout << "Freier Speicher:" << endl;
|
||||||
|
|
||||||
if (this->free_start == NULL) {
|
if (this->free_start == NULL) {
|
||||||
kout << "No free Blocks" << endl;
|
kout << " - No free Blocks" << endl;
|
||||||
} else {
|
} else {
|
||||||
kout << "Freelist start: " << hex << (unsigned int)this->free_start << endl;
|
kout << " - Freelist start: " << hex << (unsigned int)this->free_start << endl;
|
||||||
|
|
||||||
struct free_block* current = this->free_start;
|
struct free_block* current = this->free_start;
|
||||||
do {
|
do {
|
||||||
@@ -63,8 +69,6 @@ void LinkedListAllocator::dump_free_memory() {
|
|||||||
current = current->next;
|
current = current->next;
|
||||||
} while (current != free_start);
|
} while (current != free_start);
|
||||||
}
|
}
|
||||||
|
|
||||||
kout << endl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
@@ -80,7 +84,7 @@ void* LinkedListAllocator::alloc(unsigned int req_size) {
|
|||||||
kout << "Requested " << hex << req_size << " Bytes" << endl;
|
kout << "Requested " << hex << req_size << " Bytes" << endl;
|
||||||
|
|
||||||
if (this->free_start == NULL) {
|
if (this->free_start == NULL) {
|
||||||
kout << "No free memory remaining :(" << endl;
|
kout << " - No free memory remaining :(" << endl;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,24 +92,31 @@ void* LinkedListAllocator::alloc(unsigned int req_size) {
|
|||||||
do {
|
do {
|
||||||
if (current->size >= req_size) {
|
if (current->size >= req_size) {
|
||||||
// Current block large enough
|
// Current block large enough
|
||||||
|
// We now have: [<> | current | <>]
|
||||||
|
|
||||||
// Don't subtract or underflow
|
// Don't subtract to prevent underflow
|
||||||
if (current->size >= req_size + sizeof(struct free_block) + HEAP_MIN_FREE_BLOCK_SIZE) {
|
if (current->size >= req_size + sizeof(struct free_block) + HEAP_MIN_FREE_BLOCK_SIZE) {
|
||||||
// Block so large it can be cut
|
// Block so large it can be cut
|
||||||
|
|
||||||
// Create new header after allocated memory and rearrange pointers
|
// Create new header after allocated memory and rearrange pointers
|
||||||
|
// [<> | current | new_next | <>]
|
||||||
|
// In case of only one freeblock:
|
||||||
|
// [current | new_next]
|
||||||
struct free_block* new_next =
|
struct free_block* new_next =
|
||||||
(struct free_block*)((unsigned int)current + sizeof(struct free_block) + req_size);
|
(struct free_block*)((unsigned int)current + sizeof(struct free_block) + req_size);
|
||||||
|
|
||||||
|
// If only one block exists, current->next is current
|
||||||
|
// This shouldn't be a problem since the block gets removed from the list later
|
||||||
new_next->next = current->next;
|
new_next->next = current->next;
|
||||||
new_next->size = current->size - (req_size + sizeof(struct free_block));
|
new_next->size = current->size - (req_size + sizeof(struct free_block));
|
||||||
current->next = new_next;
|
|
||||||
|
current->next = new_next; // We want to reach the next free block from the allocated block
|
||||||
current->size = req_size;
|
current->size = req_size;
|
||||||
|
|
||||||
// Next-fit
|
// Next-fit
|
||||||
this->free_start = new_next;
|
this->free_start = new_next;
|
||||||
|
|
||||||
kout << "Allocated " << hex << req_size << " Bytes with cutting" << endl;
|
kout << " - Allocated " << hex << req_size << " Bytes with cutting" << endl;
|
||||||
kout << endl;
|
|
||||||
} else {
|
} else {
|
||||||
// Block too small to be cut, allocate whole block
|
// Block too small to be cut, allocate whole block
|
||||||
|
|
||||||
@@ -113,16 +124,20 @@ void* LinkedListAllocator::alloc(unsigned int req_size) {
|
|||||||
this->free_start = current->next; // Pointer keeps pointing to current if last block
|
this->free_start = current->next; // Pointer keeps pointing to current if last block
|
||||||
if (this->free_start == current) {
|
if (this->free_start == current) {
|
||||||
// No free block remaining
|
// No free block remaining
|
||||||
|
kout << " - Disabled freelist" << endl;
|
||||||
this->free_start = NULL;
|
this->free_start = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
kout << "Allocated " << hex << current->size << " Bytes without cutting" << endl;
|
kout << " - Allocated " << hex << current->size << " Bytes without cutting" << endl;
|
||||||
kout << endl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Block aushängen
|
// Block aushängen
|
||||||
struct free_block* previous = this->find_previous_block(current);
|
struct free_block* previous = this->find_previous_block(current);
|
||||||
previous->next = current->next;
|
previous->next = current->next;
|
||||||
|
current->allocated = true;
|
||||||
|
|
||||||
|
// We leave the current->next pointer intact although the block is allocated
|
||||||
|
// to allow easier merging of adjacent free blocks
|
||||||
|
|
||||||
return (void*)((unsigned int)current + sizeof(struct free_block)); // Speicheranfang, nicht header
|
return (void*)((unsigned int)current + sizeof(struct free_block)); // Speicheranfang, nicht header
|
||||||
}
|
}
|
||||||
@@ -130,8 +145,7 @@ void* LinkedListAllocator::alloc(unsigned int req_size) {
|
|||||||
current = current->next;
|
current = current->next;
|
||||||
} while (current != this->free_start); // Stop when arriving at the first block again
|
} while (current != this->free_start); // Stop when arriving at the first block again
|
||||||
|
|
||||||
kout << "More memory requested than available :(" << endl;
|
kout << " - More memory requested than available :(" << endl;
|
||||||
kout << endl;
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -144,7 +158,103 @@ void LinkedListAllocator::free(void* ptr) {
|
|||||||
|
|
||||||
/* Hier muess Code eingefuegt werden */
|
/* Hier muess Code eingefuegt werden */
|
||||||
|
|
||||||
kout << "Free not implemented (yet)" << endl;
|
kout << "Freeing " << hex << (unsigned int)ptr << endl;
|
||||||
|
|
||||||
|
struct free_block* block_start = (struct free_block*)((unsigned int)ptr - sizeof(struct free_block));
|
||||||
|
|
||||||
|
// Reenable the freelist if no block was available
|
||||||
|
// This also means that no merging can be done
|
||||||
|
if (this->free_start == NULL) {
|
||||||
|
this->free_start = block_start;
|
||||||
|
block_start->allocated = false;
|
||||||
|
block_start->next = block_start;
|
||||||
|
|
||||||
|
kout << " - Enabling freelist with one block" << endl;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct free_block* next_block =
|
||||||
|
(struct free_block*)((unsigned int)block_start + sizeof(struct free_block) + block_start->size);
|
||||||
|
|
||||||
|
// Find the next free block, multiple next blocks can be allocated so walk through them
|
||||||
|
struct free_block* next_free = block_start->next;
|
||||||
|
while (next_free->allocated) {
|
||||||
|
next_free = next_free->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct free_block* previous_free = this->find_previous_block(next_free);
|
||||||
|
struct free_block* previous_free_next =
|
||||||
|
(struct free_block*)((unsigned int)previous_free + sizeof(struct free_block) + previous_free->size);
|
||||||
|
|
||||||
|
// We have: [previous_free | previous_free_next | <> | block_start | next_block | <> | next_free]
|
||||||
|
// The <> spaces don't have to exist and next_block could be the same as next_free
|
||||||
|
// or previous_free_next the same as block_start
|
||||||
|
// Also next_block and previous_free_next could be allocated blocks
|
||||||
|
//
|
||||||
|
// If previous_free/next_free and block_start are adjacent and free, they can be merged:
|
||||||
|
// - If next_block and next_free are the same block we can merge forward
|
||||||
|
// Should result in: [previous_free | previous_free_next | <> | block_start]
|
||||||
|
// - If previous_free_next and block_start are the same block we can merge backward
|
||||||
|
// Should result in: [block_start]
|
||||||
|
|
||||||
|
// Try to merge forward ========================================================================
|
||||||
|
if (next_block == next_free) {
|
||||||
|
kout << " - Merging block forward" << endl;
|
||||||
|
|
||||||
|
// Current and next adjacent block can be merged
|
||||||
|
// [previous_free | previous_free_next | <> | block_start | next_free]
|
||||||
|
|
||||||
|
block_start->next = next_free->next; // We make next_free disappear
|
||||||
|
if (block_start->next == next_free) {
|
||||||
|
// If next_free is the only free block it points to itself, so fix that
|
||||||
|
block_start->next = block_start;
|
||||||
|
}
|
||||||
|
block_start->size = block_start->size + sizeof(struct free_block) + next_free->size;
|
||||||
|
|
||||||
|
// There shouldn't exist any other allocated blocks pointing to next_free,
|
||||||
|
// the current one should be the only one (or else I have done something wrong)
|
||||||
|
// If thats the case I should set the next pointer to the next adjacent block
|
||||||
|
// when allocating a new block
|
||||||
|
|
||||||
|
if (this->free_start == next_free) {
|
||||||
|
// next_free is now invalid after merge
|
||||||
|
kout << " - Moving freelist start to " << hex << (unsigned int)block_start << endl;
|
||||||
|
this->free_start = block_start;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Can't merge forward so size stays the same
|
||||||
|
// [previous_free | previous_free_next | <> | block_start | <> | next_free]
|
||||||
|
|
||||||
|
block_start->next = next_free;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attach new free block to freelist
|
||||||
|
// This could write into a free block, but doesn't matter
|
||||||
|
previous_free->next = block_start;
|
||||||
|
|
||||||
|
// Try to merge backward =====================================================================
|
||||||
|
if (previous_free_next == block_start) {
|
||||||
|
kout << " - Merging block backward" << endl;
|
||||||
|
|
||||||
|
// Current and previous adjacent block can be merged
|
||||||
|
// [previous_free | block_start]
|
||||||
|
|
||||||
|
previous_free->next = block_start->next;
|
||||||
|
previous_free->size = previous_free->size + sizeof(struct free_block) + block_start->size;
|
||||||
|
|
||||||
|
// For pointers to block_start the same as above applies
|
||||||
|
// so I don't think I have to manage anything else here
|
||||||
|
|
||||||
|
if (this->free_start == block_start) {
|
||||||
|
// block_start is now invalid after merge
|
||||||
|
kout << " - Moving freelist start to " << hex << (unsigned int)previous_free << endl;
|
||||||
|
this->free_start = previous_free;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Depending on the merging this might write into the block, but doesn't matter
|
||||||
|
block_start->allocated = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: I added this
|
// NOTE: I added this
|
||||||
@@ -152,7 +262,13 @@ struct free_block* LinkedListAllocator::find_previous_block(struct free_block* n
|
|||||||
// Durchlaufe die ganze freispeicherliste bis zum Block der auf next_block zeigt
|
// Durchlaufe die ganze freispeicherliste bis zum Block der auf next_block zeigt
|
||||||
struct free_block* current = next_block;
|
struct free_block* current = next_block;
|
||||||
while (current->next != next_block) {
|
while (current->next != next_block) {
|
||||||
|
// NOTE: This can get stuck if called on the wrong block
|
||||||
current = current->next;
|
current = current->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if (current == next_block) {
|
||||||
|
// kout << "LinkedListAllocator::find_previous_block returned the input block" << endl;
|
||||||
|
// }
|
||||||
|
|
||||||
return current;
|
return current;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,8 +14,9 @@
|
|||||||
|
|
||||||
#include "kernel/Allocator.h"
|
#include "kernel/Allocator.h"
|
||||||
|
|
||||||
// Format eines freien Blocks, 4 + 4 Byte
|
// Format eines freien Blocks, 4 + 4 + 4 Byte
|
||||||
struct free_block {
|
struct free_block {
|
||||||
|
bool allocated; // NOTE: I added this to allow easier merging of free blocks
|
||||||
unsigned int size;
|
unsigned int size;
|
||||||
struct free_block* next;
|
struct free_block* next;
|
||||||
};
|
};
|
||||||
|
|||||||
+40
-3
@@ -20,7 +20,7 @@ void waitForReturn() {
|
|||||||
|
|
||||||
Key key;
|
Key key;
|
||||||
do {
|
do {
|
||||||
kb.key_hit();
|
key = kb.key_hit();
|
||||||
} while (key.ascii() != '\n');
|
} while (key.ascii() != '\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -29,9 +29,46 @@ void heap_demo() {
|
|||||||
/* hier muss Code eingefuegt werden */
|
/* hier muss Code eingefuegt werden */
|
||||||
allocator.dump_free_memory();
|
allocator.dump_free_memory();
|
||||||
|
|
||||||
|
// Some objects and forward/backward merging
|
||||||
MyObj* a = new MyObj(5);
|
MyObj* a = new MyObj(5);
|
||||||
|
// allocator.dump_free_memory();
|
||||||
|
MyObj* b = new MyObj(10);
|
||||||
|
// allocator.dump_free_memory();
|
||||||
|
MyObj* c = new MyObj(15);
|
||||||
|
allocator.dump_free_memory();
|
||||||
|
delete b;
|
||||||
|
// allocator.dump_free_memory();
|
||||||
|
delete a;
|
||||||
|
// allocator.dump_free_memory();
|
||||||
|
delete c;
|
||||||
allocator.dump_free_memory();
|
allocator.dump_free_memory();
|
||||||
|
|
||||||
allocator.alloc(1024 * 1024 - 16); // should fail as only 1024 * 1024 - (4 + 4) bytes remain
|
// Allocate too whole heap
|
||||||
allocator.dump_free_memory();
|
// void* ptr = allocator.alloc(1024 * 1024 - 24);
|
||||||
|
// allocator.dump_free_memory();
|
||||||
|
// allocator.free(ptr);
|
||||||
|
// allocator.dump_free_memory();
|
||||||
|
|
||||||
|
// Allocate too much
|
||||||
|
// allocator.alloc(1024 * 1024); // should fail as only 1024 * 1024 - Headersize bytes are available
|
||||||
|
// allocator.dump_free_memory();
|
||||||
|
|
||||||
|
// A lot of allocations
|
||||||
|
// MyObj* objs[1024];
|
||||||
|
// for (unsigned int i = 0; i < 1024; ++i) {
|
||||||
|
// // This tries allocates a lot more than possible
|
||||||
|
// objs[i] = new MyObj(5);
|
||||||
|
// }
|
||||||
|
// allocator.dump_free_memory();
|
||||||
|
// waitForReturn();
|
||||||
|
// for (unsigned int i = 0; i < 1024; ++i) {
|
||||||
|
// delete objs[i];
|
||||||
|
// }
|
||||||
|
// allocator.dump_free_memory();
|
||||||
|
|
||||||
|
// Array allocation
|
||||||
|
// MyObj* objs = new MyObj[1024];
|
||||||
|
// allocator.dump_free_memory();
|
||||||
|
// delete[] objs;
|
||||||
|
// allocator.dump_free_memory();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
class MyObj {
|
class MyObj {
|
||||||
public:
|
public:
|
||||||
|
MyObj() : value(5) {};
|
||||||
MyObj(unsigned int val) : value(val) {};
|
MyObj(unsigned int val) : value(val) {};
|
||||||
unsigned int value;
|
unsigned int value;
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user