From f3e47f406dc23b456dbe2a71504556eb0544992b Mon Sep 17 00:00:00 2001 From: awenchen Date: Sun, 17 May 2020 13:10:49 +0800 Subject: [PATCH] Upgrade the implementation of dynamic memory allocator: 1. Allocate memory with alignment in case of the crash in some embedded system; 2. Free memory without coalesce the next node(or previous node) when the current node is the last one(or first one); 3. Add declaration of function get_best_fit in case of crash in 64bits platform; 4. Fix the dump of pointer in main.c; --- commented_heap.c | 64 +++++++++++++++++++++++++++++------------------- heap.c | 46 ++++++++++++++++++++++------------ include/heap.h | 3 +++ main.c | 16 ++++++------ 4 files changed, 80 insertions(+), 49 deletions(-) diff --git a/commented_heap.c b/commented_heap.c index 59731a2..0dd1cd2 100644 --- a/commented_heap.c +++ b/commented_heap.c @@ -1,6 +1,6 @@ #include "include/heap.h" -int offset = sizeof(int) * 2; +#define USER_POINTER_OFFSET (2 * sizeof(int)) // ======================================================== // this function initializes a new heap structure, provided @@ -10,7 +10,7 @@ int offset = sizeof(int) * 2; // how large the heap is so make sure the same constant // is used when allocating memory for your heap! // ======================================================== -void init_heap(heap_t *heap, int start) { +void init_heap(heap_t *heap, long start) { // first we create the initial region, this is the "wilderness" chunk // the heap starts as just one big chunk of allocatable memory node_t *init_region = (node_t *) start; @@ -34,11 +34,20 @@ void init_heap(heap_t *heap, int start) { // if neccesary and return the start of the chunk // ======================================================== void *heap_alloc(heap_t *heap, size_t size) { + uint index = 0; + bin_t *temp = NULL; + node_t *found = NULL; + + // do alignment first + if (ALIGN_BTYES != 1) { + size = ((size + ALIGN_BTYES - 1) / ALIGN_BTYES) * ALIGN_BTYES; + } + // first get the bin index that this chunk size should be in - int index = get_bin_index(size); + index = get_bin_index(size); // now use this bin to try and find a good fitting chunk! - bin_t *temp = (bin_t *) heap->bins[index]; - node_t *found = get_best_fit(temp, size); + temp = (bin_t *) heap->bins[index]; + found = get_best_fit(temp, size); // while no chunk if found advance through the bins until we // find a chunk or get to the wilderness @@ -103,29 +112,34 @@ void *heap_alloc(heap_t *heap, size_t size) { // coalesced and then placed in the correct bin // ======================================================== void heap_free(heap_t *heap, void *p) { - bin_t *list; - footer_t *new_foot, *old_foot; + bin_t *list = NULL; + footer_t *new_foot = NULL; + footer_t *old_foot = NULL; + footer_t *f = NULL; + node_t *prev = NULL; + int has_next = 0; + int has_prev = 0; // the actual head of the node is not p, it is p minus the size // of the fields that precede "next" in the node structure - // if the node being free is the start of the heap then there is - // no need to coalesce so just put it in the right list - node_t *head = (node_t *) ((char *) p - offset); - if (head == heap->start) { - head->hole = 1; - add_node(heap->bins[get_bin_index(head->size)], head); - return; + // if the node being free is the start of the heap, it would has + // no previous node to coalesce + node_t *head = (node_t *) ((char *) p - USER_POINTER_OFFSET); + if (head != (node_t *)(uintptr_t) heap->start) { + has_prev = 1; + f = (footer_t *) ((char *) head - sizeof(footer_t)); + prev = f->header; } - // these are the next and previous nodes in the heap, not the prev and next - // in a bin. to find prev we just get subtract from the start of the head node - // to get the footer of the previous node (which gives us the header pointer). - // to get the next node we simply get the footer and add the sizeof(footer_t). + // if the node being free is the end of the heap, it would has + // no next node to coalesce node_t *next = (node_t *) ((char *) get_foot(head) + sizeof(footer_t)); - node_t *prev = (node_t *) * ((int *) ((char *) head - sizeof(footer_t))); + if (next != (node_t *) (uintptr_t)heap->end) { + has_next = 1; + } - // if the previous node is a hole we can coalese! - if (prev->hole) { + // if it has the previous node and the previous node is a hole we can coalese! + if (has_prev && prev->hole) { // remove the previous node from its bin list = heap->bins[get_bin_index(prev->size)]; remove_node(list, prev); @@ -140,8 +154,8 @@ void heap_free(heap_t *heap, void *p) { head = prev; } - // if the next node is free coalesce! - if (next->hole) { + // if it has the next node and the next node is free coalesce! + if (has_next && next->hole) { // remove it from its bin list = heap->bins[get_bin_index(next->size)]; remove_node(list, next); @@ -165,7 +179,7 @@ void heap_free(heap_t *heap, void *p) { } // these are left here to implement contraction / expansion -int expand(heap_t *heap, size_t sz) { +uint expand(heap_t *heap, size_t sz) { } @@ -179,7 +193,7 @@ void contract(heap_t *heap, size_t sz) { // places any allocation < 8 in bin 0 and then for anything // above 8 it bins using the log base 2 of the size // ======================================================== -int get_bin_index(size_t sz) { +uint get_bin_index(size_t sz) { int index = 0; sz = sz < 4 ? 4 : sz; diff --git a/heap.c b/heap.c index 049ab14..98ccd14 100644 --- a/heap.c +++ b/heap.c @@ -1,7 +1,7 @@ #include "include/heap.h" #include "include/llist.h" -uint offset = 8; +#define USER_POINTER_OFFSET (2 * sizeof(int)) void init_heap(heap_t *heap, long start) { node_t *init_region = (node_t *) start; @@ -17,9 +17,17 @@ void init_heap(heap_t *heap, long start) { } void *heap_alloc(heap_t *heap, size_t size) { - uint index = get_bin_index(size); - bin_t *temp = (bin_t *) heap->bins[index]; - node_t *found = get_best_fit(temp, size); + uint index = 0; + bin_t *temp = NULL; + node_t *found = NULL; + + if (ALIGN_BTYES != 1) { + size = ((size + ALIGN_BTYES - 1) / ALIGN_BTYES) * ALIGN_BTYES; + } + + index = get_bin_index(size); + temp = (bin_t *) heap->bins[index]; + found = get_best_fit(temp, size); while (found == NULL) { if (index + 1 >= BIN_COUNT) @@ -64,21 +72,27 @@ void *heap_alloc(heap_t *heap, size_t size) { } void heap_free(heap_t *heap, void *p) { - bin_t *list; - footer_t *new_foot, *old_foot; - - node_t *head = (node_t *) ((char *) p - offset); - if (head == (node_t *) (uintptr_t) heap->start) { - head->hole = 1; - add_node(heap->bins[get_bin_index(head->size)], head); - return; + bin_t *list = NULL; + footer_t *new_foot = NULL; + footer_t *old_foot = NULL; + footer_t *f = NULL; + node_t *prev = NULL; + int has_next = 0; + int has_prev = 0; + + node_t *head = (node_t *) ((char *) p - USER_POINTER_OFFSET); + if (head != (node_t *)(uintptr_t) heap->start) { + has_prev = 1; + f = (footer_t *) ((char *) head - sizeof(footer_t)); + prev = f->header; } node_t *next = (node_t *) ((char *) get_foot(head) + sizeof(footer_t)); - footer_t *f = (footer_t *) ((char *) head - sizeof(footer_t)); - node_t *prev = f->header; + if (next != (node_t *) (uintptr_t)heap->end) { + has_next = 1; + } - if (prev->hole) { + if (has_prev && prev->hole) { list = heap->bins[get_bin_index(prev->size)]; remove_node(list, prev); @@ -89,7 +103,7 @@ void heap_free(heap_t *heap, void *p) { head = prev; } - if (next->hole) { + if (has_next && next->hole) { list = heap->bins[get_bin_index(next->size)]; remove_node(list, next); diff --git a/include/heap.h b/include/heap.h index e9b44c5..cf52df6 100644 --- a/include/heap.h +++ b/include/heap.h @@ -16,6 +16,8 @@ #define BIN_COUNT 9 #define BIN_MAX_IDX (BIN_COUNT - 1) +#define ALIGN_BTYES sizeof(long) /* alignment bytes */ + typedef unsigned int uint; typedef struct node_t { @@ -49,6 +51,7 @@ uint expand(heap_t *heap, size_t sz); void contract(heap_t *heap, size_t sz); uint get_bin_index(size_t sz); +node_t *get_best_fit(bin_t *bin, size_t size); void create_foot(node_t *head); footer_t *get_foot(node_t *head); diff --git a/main.c b/main.c index b1c1712..973dd1a 100644 --- a/main.c +++ b/main.c @@ -22,26 +22,26 @@ int main(int argc, char** argv) { printf("overhead = %d \n", overhead); void *a = heap_alloc(heap, 8); - printf("a = %d size: 8 \n", (int) a); + printf("a = %p size: 8 \n", a); void *b = heap_alloc(heap, 128); - printf("b = %d size: 128 \n", (int) b); + printf("b = %p size: 128 \n", b); void *c = heap_alloc(heap, 8); - printf("c = %d size: 8 \n", (int) c); + printf("c = %p size: 8 \n", c); printf("\nfreeing b \n"); heap_free(heap, b); void* d = heap_alloc(heap, 8); - printf("d = %d size: 8 \n", (int) d); + printf("d = %p size: 8 \n", d); void* e = heap_alloc(heap, 16); - printf("e = %d size: 16 \n", (int) e); + printf("e = %p size: 16 \n", e); void* f = heap_alloc(heap, 8); - printf("f = %d size: 8 \n", (int) f); + printf("f = %p size: 8 \n", f); void* g = heap_alloc(heap, 8); - printf("g = %d size: 8 \n", (int) g); + printf("g = %p size: 8 \n", g); printf("\nfreeing d & f \n"); heap_free(heap, d); @@ -51,7 +51,7 @@ int main(int argc, char** argv) { heap_free(heap, e); void* h = heap_alloc(heap, 128); - printf("h = %d size: 128 \n", (int) h); + printf("h = %p size: 128 \n", h); printf("\n"); for (i = 1; i <= 2048; i += i) printf("size: %d -> bin: %d \n", i, get_bin_index(i));