再看上图的右边,就是上面提到的vitual table,这个是调用MemoryContextCreate()传进去的第三个参数AllocSetMethods,这是一个MemoryContextMethods类型的静态全局变量, 根据这个变量的定义(在下面)就可以看出这是一个为AllocSet Context管理内存的虚拟函数的表(vitual function table),MemoryContextMethods结构里定义了这些函数原型。这些函数实现了pg对内存的管理,整个就是pg的AllocSet和MemoryContext的内存空间管理机制。
静态全局变量AllocSetMethods的定义:
static MemoryContextMethods AllocSetMethods = {
AllocSetAlloc,
AllocSetFree,
AllocSetRealloc,
AllocSetInit,
AllocSetReset,
AllocSetDelete,
AllocSetGetChunkSpace,
AllocSetIsEmpty,
AllocSetStats,
#ifdef MEMORY_CONTEXT_CHECKING
,AllocSetCheck
#endif
};
结构MemoryContextMethods的定义:
typedef struct MemoryContextMethods
{
void *(*alloc) (MemoryContext context, Size size);
/*call this free_p in case someone #define's free() */
void (*free_p) (MemoryContext context, void *pointer);
void *(*realloc) (MemoryContext context, void*pointer, Size size);
void (*init) (MemoryContext context);
void (*reset) (MemoryContext context);
void (*delete)(MemoryContext context);
Size (*get_chunk_space) (MemoryContext context, void *pointer);
bool (*is_empty) (MemoryContext context);
void (*stats) (MemoryContext context);
#ifdef MEMORY_CONTEXT_CHECKING
void (*check) (MemoryContext context);
#endif
}MemoryContextMethods;
从pg中使用这些函数的情况来看,这些方法在MemoryContext中定义,在AllocSet中实现和使用,又像子类实现父类的虚拟方法,又是面向对象编程的影子。面向过程编程中的编程技巧在面向对象编程中基本上都成了编程语言的内在机制了。台湾的侯捷先生说要写一本《c语言高级编程》的书也有十来年了吧,到现在都没出,是否有这个原因呢
至此,TopMemoryContext初始化完成了,里面的其他属性就不写了。有了前面内容垫底,初始化ErrorContext就好写多了,因为它的类型和TomMemoryContext是一样的。
3 初始化ErrorContext的过程
先看看MemoryContextInit()的代码,这个很简洁,就是初始化TopMemoryContext和ErrorContext,完事。为了省地,把注释删了。在AllocSetContextCreate()中对TopMemoryContext和ErrorContext的处理基本上是一样的。在MemoryContextCreate()中则有些不同,判断TopMemoryContext非空后就去调用另一个函数MemoryContextAlloc(),这个函数没干什么事,直接调用上面提到的虚拟方法表中的Alloc函数,它的具体实现是AllocSetAlloc()函数,在其中分配好空间,初始化和设置AllocBlock和AllocChunk的属性,然后返回。接着在MemorycontextCreate()处理MemoryContextData结构的属性,其中把ErrorContext的parent指向TopMemoryContext,处理完MemoryContextData的属性后返回返回到AllocSetContextCreate(),设置AllocSetContext的属性,这样就完成了ErrorContext的初始化。
AllocSetAlloc()这个函数是pg中实际处理AllocSet和MemoryContext涉及的内存空间分配的函数,这个分配机制比较复杂,还涉及到了另外两个结构AllocBlock和AllocChunk,写pg的内存空间分配机制时再写吧。
下面上初始化完以后的内存结构图
TopMemoryContext和ErrorContext的结构图一
上图中紫色的那一块是AllocBlock,中间浅紫色的那一小块是AllocChunk。
只有两个MemoryContext图就看着有点眼花缭乱了,看来以后得画抽象图了。
pg的内存管理主要是棵树,TopMemoryContext是树根,后面再建的MemoryContext就在根的下面。pg的内存管理实际是一个图,其主要部分是树形结构,另外子节点的partent指向了TopMemoryContext,形成了环。这样整个构成了图。这样的结构便于数据库的内存管理。
AllocSetContext中blocks记录了分配给该Context的内存空间块AllockBlock的单向链表,freelist是空闲AllocChunk的链表数组。pg中给context分配内存时先分配AllockBlock,在AllockBlock里再分配AllocChunk,就是说AllocChunk是比AllockBlock小一级的内存空间单位。
上图中的ErrorContext所占的内存空间实际上在浅紫色的AllocChunk里,不是在外边,到写内存分配的时候再深入。上图是为了看清楚AllocBlock和AllocChunk,没有把ErrorContext放到AllocChunk里,实际见下面这个图。

TopMemoryContext和ErrorContext的结构图二
TopMemoryContext和ErrorContext初始化完后的内存物理布局图,嗯,嗯,嗯,这个画着好费时费力,嗯,还好,有人画了,如下: