本章开头指出上一章节描述的内存管理方法存在一些缺陷,比如不适合频繁创建和销毁内存的应用场景;所以在本章重新给出了另外一种设计思路。提出了内存池的概念,如果熟悉的小伙伴,还接触过线程池的概念。个人认为这一章节比前一章节更好理解。
本书中的代码有个地方的设计容易让人误解,在头文件中代码如下
#ifndef ARENA_INCLUDED
#define ARENA_INCLUDED
#include "except.h"
#define T Arean_T
// T* 和T名字一样,这样设计让人费解
typedef struct T *T;
extern const Except_T Arena_NewFailed;
extern const Except_T Arena_Failed;
extern T Arean_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);
#endif
在源文件arena.c中也有宏定义
#define T Arena_T
这样就不容易分清楚代码中T是如何替换的,核对书中给的代码,可以看出凡是T前面含struct的则会用宏定义替代,即Arena_T,凡是无struct的会被typedef struct T* T替代,如下代码所示
struct T
{
T prev; // 这里的T,由typedef struct T* T替代
// 替换后为 Arena_T * prev;
char *avail;
char *limit;
};
union header
{
struct T b; // 这里的T会被#define T Arena_T替代
// 替代后为struct Arena_T b;
union align a;
};
而且gcc编译器,创建结构体后定义结构体变量时如果不加struct会报错,如下面举例代码
struct st_tmp
{
int idata;
};
// 有的gcc编译器在缺少struct的情况下会报错
static st_tmp tmp_a;
static struct st_tmp tmp_b;
所以在书中给的代码进一步验证,如果不带struct,则由struct T *替代,而T则再次替换为Arena_T替换。
替换后的头文件为
arena_l.h
#ifndef ARENA_INCLUDED
#define ARENA_INCLUDED
#include "../../include/except.h"
#define T Arena_T
typedef struct T* PT;
extern const struct Except_T Arena_NewFailed;
extern const struct Except_T Arena_Failed;
extern struct Arena_T* Arean_new (void);
extern void Arena_dispose(struct Arena_T* *ap);
extern void *Arena_alloc(struct Arena_T* arena, long nbytes, const char *file, int line);
extern void *Arena_calloc(struct Arena_T* arena, long count, long nbytes, const char *file, int line);
extern void Arena_free(struct Arena_T* arena);
#define NEW(t,p) \
((p) = Arena_alloc(t, sizeof(*(p)), __FILE__, __LINE__))
#undef T