Code Monkey home page Code Monkey logo

tinyalloc's Introduction

thi.ng/tinyalloc

Tiny replacement for malloc / free in unmanaged, linear memory situations, e.g. WASM and embedded devices.

Updates

For an updated version (written in TypeScript, but still targetting the same linear memory setup) with more features and improved block splitting/coalescing, please visit: thi.ng/malloc.

For an in-depth discussion and comparison with other allocators, please see:

Features

  • 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
  • optional block splitting during alloc (if re-using larger free'd blocks)
  • tiny, the WASM binary is 1.5KB (1.1KB w/ compaction disabled)

Details

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 listed below. During initialization all blocks are added to the list of fresh blocks.

The difference between free & fresh blocks is the former already have an associated heap address and size from previous usage. OTOH fresh blocks are uninitialized and are only used if no existing free blocks satisfy an allocation request.

The diagram illustrates the state of having 1 freed block (green), 2 used blocks (red) and the beginning of the fresh (unused) block list:

memory layout

Allocation

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_THRESH), 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. Also, allocation will fail when all blocks in the fixed size block array are used, even though there might still be ample space in the heap memory region...

Freeing & compaction

The list of freed blocks is sorted by block start address. When a block is being freed, tinyalloc uses insertion sort to add the block at the right list position and then runs a compaction procedure, merging blocks as long as they form consecutive chunks of memory (with no gaps in between them). The resulting obsolete blocks are re-added to the list of available blocks.

API

ta_init(void *base, void *limit, size_t heap_blocks, size_t split_thresh, size_t alignment)

Initializes the control datastructure. MUST be called prior to any other tinyalloc function.

Argument Description
base Address of tinyalloc control structure, typically at the beginning of your heap
limit Heap space end address
heap_blocks Max. number of memory chunks (e.g. 256)
split_thresh Size threshold for splitting chunks (a good default is 16)
alignment Word size for pointer alignment (e.g. 8)
  • alignment is assumed to be >= native word size
  • base must be an address in RAM (on embedded devices)

void* ta_alloc(size_t num)

Like standard malloc, returns aligned pointer to address in heap space, or NULL if allocation failed.

void* ta_calloc(size_t num, size_t t)

Like standard calloc, returns aligned pointer to zeroed memory in heap space, or NULL if allocation failed.

bool ta_free(void *ptr)

Like free, but returns boolean result (true, if freeing succeeded). By default, any consecutive memory blocks are being merged during the freeing operation.

bool ta_check()

Structural validation. Returns true if internal heap structure is ok.

Building

Configuration

Define Default Comment
TA_DEBUG undefined Trace debug information
TA_DISABLE_COMPACT undefined Disable free block compaction
TA_DISABLE_SPLIT undefined Disable free block splitting during re-alloc

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:

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

(Requires emscripten)

emcc -Oz -s WASM=1 -s SIDE_MODULE=1 -o tinyalloc.wasm tinyalloc.c

Disassemble to WAST

(Requires WABT)

wasm2wast --generate-names tinyalloc.wasm > tinyalloc.wast

License

© 2016 - 2017 Karsten Schmidt - Apache Software License 2.0 (see LICENSE)

tinyalloc's People

Contributors

0xflotus avatar llucinat avatar postspectacular avatar pusnow avatar ryzee119 avatar silentcarl avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

tinyalloc's Issues

ta_alloc(0) leads to returning same non-NULL address twice

Calling ta_alloc(0) and then another ta_alloc() (of any size) appears to be returning the same address twice. Having two memory blocks sharing the same address is bad since there is no way for ta_free() to know which to free.

ta_alloc(0) should probably either return NULL or behave the same as if ta_alloc(1) was called.

Error in ta_init()

In function ta_init() the line
heap->fresh = heap->blocks;
appears before heap->blocks has been assigned.

Preventing interference WASM stack (Clang/LLVM)

I'm compiling to WASM with Clang/LLVM, not Emscripten, and was hoping to use tinyalloc. Going off of the information in this article, specifically the image indicating the data, stack, and heap layouts, it is stated that the .data section comes first, followed by the stack, and then the heap. Notice that the stack grows downwards toward __data_end.

memory layout

(I couldn't find documentation describing Emscripten's memory layout, so I'm not sure if this is the same or different than Emscripten).

That leaves me with a few questions:

  1. __data_end is typically 0x400, which is used for TA_BASE. If I place TA_BASE at 0x400, aren't I at risk of having the tinyalloc blocks clobbered by a stack that grows all the way to __data_end?
  2. For my specific application, I have a lot of static strings compiled into my program, and therefore my .data section is much larger than 0x400, but I don't necessarily know the exact size at compile time (obviously using 0x400 for TA_BASE was overwriting some of my static data). Is it feasible to define a TA_BASE at runtime as part of ta_init(), or are there some reasons that it must be defined at compile time that I just don't understand?
  3. If it's feasible to set TA_BASE and TA_HEAP_START at runtime, I was thinking that it might be a good idea to set TA_BASE to __heap_base and TA_HEAP_START to __heap_base + sizeof(Heap) so that it can grow without interference to the stack and data sections.

If these seem like valuable additions to the project, I'd be happy to take a stab at implementing them in such a way that these things can be configured when calling ta_init() and submitting a PR.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.