1、This chapter describes a memory-management interface and an imple-mentation that uses arena-based algorithms, which allocate memory from an arena and deallocate entire arenas at once.
2、With the arena-based allocator, there’s no obligation to call free for every call to malloc ; there’s only a single call that deallocates all the memory allocated in an arena since the last deallocation.
arena的基本思想就是“以栈的形式不断申请新的空间,然后一次性释放内存”。我们可以通过如下图可以看出内存的分布图:
================================arena.h===============================
#ifndef ARENA_INCLUDED #define ARENA_INCLUDED #include "except.h" #define T Arena_T typedef struct T *T; extern const Except_T Arena_NewFailed; extern const Except_T Arena_Failed; //exported functions extern T Arena_new (void); extern void Arena_dispose(T *ap); extern void *Arena_alloc (T arena, long nbytes, const char *file, int line); extern void *Arena_calloc (T arena, long count, long nbytes, const char *file, int line); extern void Arena_free (T arena); #undef T #endif
#include <stdlib.h> #include <string.h> #include "assert.h" #include "except.h" #include "arena.h" #define T Arena_T const Except_T Arena_NewFailed = { "Arena Creation Failed" }; const Except_T Arena_Failed = { "Arena Allocation Failed" }; //macros #define THRESHOLD 10 //types struct T{ T prev; char *avail; char *limit; }; union align{ int i; long l; long *lp; void *p; void (*fp)(void); float f; double d; long double ld; }; union header{ struct T b; union align a; }; //data static T freechunks; static int nfree; //functions T Arena_new(void){ T arena = malloc(sizeof (*arena)); if(arena == NULL) RAISE(Arena_NewFailed); arena->prev = NULL; arena->limit = arena->avail = NULL; return arena; } void Arena_dispose(T *ap){ assert(ap && *ap); Arena_free(*ap); free(*ap); *ap = NULL; } void *Arena_alloc(T arena, long nbytes, const char *file, int line){ assert(arena); assert(nbytes > 0); //round nbytes up to an alignment boundary nbytes = ((nbytes + sizeof(union align) - 1) / (sizeof (union align))) * (sizeof (union align)); while(nbytes > arena->limit - arena->avail){ //get a new chunk T ptr; char *limit; //ptr<-a new chunk if((ptr = freechunks) != NULL){ freechunks = freechunks->prev; nfree--; limit = ptr->limit; }else{ long m = sizeof (union header) + nbytes + 10*1024; ptr = malloc(m); if(ptr == NULL) { if(file == NULL) RAISE(Arena_Failed); else Except_raise(&Arena_Failed, file, line); } limit = (char *)ptr + m; } *ptr = *arena; arena->avail = (char *)((union header *)ptr + 1); arena->limit = limit; arena->prev = ptr; } arena->avail += nbytes; return arena->avail - nbytes; } void *Arena_calloc(T arena, long count, long nbytes, const char *file, int line){ void *ptr; assert(count > 0); ptr = Arena_alloc(arena, count*nbytes, file, line); memset(ptr, '\0', count*nbytes); return ptr; } void Arena_free(T arena){ assert(arena); while(arena->prev){ struct T tmp = *arena->prev; //free the chunk described by arena if(nfree < THRESHOLD){ arena->prev->prev = freechunks; freechunks = arena->prev; nfree++; freechunks->limit = arena->limit; }else{ free(arena->prev); } *arena = tmp; } assert(arena->limit == NULL); assert(arena->avail == NULL); }