diff options
| author | Karsten Schmidt <k@postspectacular.com> | 2017-07-14 21:14:55 +0100 |
|---|---|---|
| committer | Karsten Schmidt <k@postspectacular.com> | 2017-07-14 21:14:55 +0100 |
| commit | 1c06015c61c0b5b1a3e67f87b13d73c57209d59d (patch) | |
| tree | 3e5b2d2b1559c53c15214a58eb15387a4b1b67f6 | |
| parent | 11fdb10451c8cf1ecc4e65ae9da45b8c7e95a50d (diff) | |
update readme, add mem layout diag, rename defines & heap struct fields
| -rw-r--r-- | README.md | 20 | ||||
| -rw-r--r-- | tinyalloc.c | 40 | ||||
| -rw-r--r-- | tinyalloc.h | 4 | ||||
| -rw-r--r-- | tinyalloc.png | bin | 0 -> 154707 bytes | |||
| -rw-r--r-- | tinyalloc.xml | 1 |
5 files changed, 37 insertions, 28 deletions
@@ -4,7 +4,7 @@ Tiny replacement for `malloc` / `free` in unmanaged, linear memory situations, e ## Features -- written in C11, no dependencies or syscalls +- written in standalone C11, no dependencies, C runtime or syscalls used - configurable address region (and max. block count) for heap space - configurable pointer alignment in heap space - optional compaction of consecutive free blocks @@ -13,11 +13,13 @@ Tiny replacement for `malloc` / `free` in unmanaged, linear memory situations, e ## Details -**tinyalloc** maintains 3 linked lists: available blocks, used blocks, free blocks. All lists are stored in the same fixed sized array, so the memory overhead can be controlled at compile time via the [configuration vars](#configuration) listed below. During initialization all blocks are added to the list of available blocks. +**tinyalloc** maintains 3 linked lists: fresh blocks, used blocks, free blocks. All lists are stored in the same fixed sized array so the memory overhead can be controlled at compile time via the [configuration vars](#configuration) listed below. During initialization all blocks are added to the list of available blocks. + + ### Allocation -When a new chunk of memory is requested, all previously freed blocks are checked for potential re-use. If a block is found and larger than the requested size and the size difference is greater than the configured threshold (`TA_SPLIT_THRESHOLD`), the existing block is first split, the chunks are added to the used & free lists respectively and the pointer to the first chunk returned to the user. If no blocks in the free list qualify, a new block is allocated at the current heap top address, moved from the "available" to the "used" block list and the pointer returned to the caller. +When a new chunk of memory is requested, all previously freed blocks are checked for potential re-use. If a block is found, is larger than the requested size and the size difference is greater than the configured threshold (`TA_SPLIT_THRESHOLD`), then the block is first split, the chunks added to the used & free lists respectively and the pointer to the first chunk returned to the user. If no blocks in the free list qualify, a new block is allocated at the current heap top address, moved from the "fresh" to the "used" block list and the pointer returned to the caller. Note: All returned pointers are aligned to `TA_ALIGN` word boundaries. Same goes for allocated block sizes. @@ -55,17 +57,23 @@ Structural validation. Returns `true` if internal heap structure is ok. |--------|---------|---------| | `TA_ALIGN` | 8 | Word size for pointer alignment | | `TA_BASE` | 0x400 | Address of **tinyalloc** control data structure | +| `TA_DEBUG` | undefined | Trace debug information | | `TA_HEAP_START` | 0x1010 | Heap space start address | -| `TA_HEAP_LIMIT` | 0x1000000 | Heap space end address | +| `TA_HEAP_LIMIT` | 0xffffff | Heap space end address | | `TA_HEAP_BLOCKS` | 256 | Max. number of memory chunks | -| `TA_SPLIT_THRESHOLD` | 16 | Size threshold for splitting chunks | +| `TA_SPLIT_THRESH` | 16 | Size threshold for splitting chunks | + +On a 32bit system, the default configuration causes an overhead of 3088 bytes in RAM, but can be reduced if fewer memory blocks are needed. **Notes:** - `TA_ALIGN` is assumed to be >= native word size - `TA_HEAP_START` is assumed to be properly aligned -On a 32bit system, the default configuration causes an overhead of 3088 bytes in RAM, but can be reduced if fewer memory blocks are needed. +If building in debug mode (if `TA_DEBUG` symbol is defined), two externally defined functions are required: + +- `print_s(char *)` - to print a single string +- `print_i(size_t)` - to print a single unsigned int ### Building for WASM diff --git a/tinyalloc.c b/tinyalloc.c index b48f85c..1eeb614 100644 --- a/tinyalloc.c +++ b/tinyalloc.c @@ -1,11 +1,11 @@ #include "tinyalloc.h" -#ifdef NDEBUG -#define print_s(X) -#define print_i(X) -#else +#ifdef TA_DEBUG extern void print_s(char *); extern void print_i(size_t); +#else +#define print_s(X) +#define print_i(X) #endif typedef struct Block Block; @@ -19,7 +19,7 @@ struct Block { typedef struct { Block *free; // first free block Block *used; // first used block - Block *avail; // first available blank block + Block *fresh; // first available blank block size_t top; // top free addr Block blocks[TA_HEAP_BLOCKS]; } Heap; @@ -59,10 +59,10 @@ static void release_blocks(Block *scan, Block *to) { print_s("release"); print_i((size_t)scan); scan_next = scan->next; - scan->next = heap->avail; + scan->next = heap->fresh; scan->addr = 0; scan->size = 0; - heap->avail = scan; + heap->fresh = scan; scan = scan_next; } } @@ -102,11 +102,11 @@ static void compact() { bool ta_init() { heap->free = NULL; heap->used = NULL; - heap->avail = heap->blocks; + heap->fresh = heap->blocks; heap->top = TA_HEAP_START; Block *block = heap->blocks; - size_t i = TA_HEAP_BLOCKS - 1; - while(i--) { + size_t i = TA_HEAP_BLOCKS - 1; + while (i--) { block->next = block + 1; block++; } @@ -152,12 +152,12 @@ static Block *alloc_block(size_t num) { print_s("resize top block"); ptr->size = num; heap->top = (size_t)ptr->addr + num; - } else if (heap->avail != NULL) { + } else if (heap->fresh != NULL) { size_t excess = ptr->size - num; - if (excess >= TA_SIZE_THRESHOLD) { + if (excess >= TA_SPLIT_THRESH) { ptr->size = num; - Block *split = heap->avail; - heap->avail = split->next; + Block *split = heap->fresh; + heap->fresh = split->next; split->addr = ptr->addr + num; print_s("split"); print_i((size_t)split->addr); @@ -174,9 +174,9 @@ static Block *alloc_block(size_t num) { // no matching free blocks // see if any other blocks available size_t new_top = top + num; - if (heap->avail != NULL && new_top <= TA_HEAP_LIMIT) { - ptr = heap->avail; - heap->avail = ptr->next; + if (heap->fresh != NULL && new_top <= TA_HEAP_LIMIT) { + ptr = heap->fresh; + heap->fresh = ptr->next; ptr->addr = (void *)top; ptr->next = heap->used; ptr->size = num; @@ -200,9 +200,9 @@ static void memset(void *ptr, uint8_t c, size_t num) { size_t numw = (num & -sizeof(size_t)) / sizeof(size_t); size_t cw = c; cw = (cw << 24) | (cw << 16) | (cw << 8) | cw; - #ifdef __LP64__ +#ifdef __LP64__ cw |= (cw << 32); - #endif +#endif while (numw--) { *ptrw++ = cw; } @@ -241,7 +241,7 @@ size_t ta_num_used() { } size_t ta_num_avail() { - return count_blocks(heap->avail); + return count_blocks(heap->fresh); } bool ta_check() { diff --git a/tinyalloc.h b/tinyalloc.h index 73e2b74..997dc74 100644 --- a/tinyalloc.h +++ b/tinyalloc.h @@ -22,8 +22,8 @@ #define TA_HEAP_BLOCKS 256 #endif -#ifndef TA_SIZE_THRESHOLD -#define TA_SIZE_THRESHOLD 16 +#ifndef TA_SPLIT_THRESH +#define TA_SPLIT_THRESH 16 #endif bool ta_init(); diff --git a/tinyalloc.png b/tinyalloc.png Binary files differnew file mode 100644 index 0000000..2c50c58 --- /dev/null +++ b/tinyalloc.png diff --git a/tinyalloc.xml b/tinyalloc.xml new file mode 100644 index 0000000..b9d986d --- /dev/null +++ b/tinyalloc.xml @@ -0,0 +1 @@ +<mxfile userAgent="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36" version="6.8.15" editor="www.draw.io" type="device"><diagram id="b87d4dbe-5297-3cd3-d217-58009162e719" name="Page-1">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</diagram></mxfile>
\ No newline at end of file |
