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
==============================arena.c==============================
#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);
}