MemoryContext 是 PG 内存上下文管理模块,内核代码可以在指定的 MemoryContext 上动态分配内存,扩容内存以及释放内存,使用 MemoryContext 便于内存管理,内存使用统计以及防止内存泄露。
PG 内核代码中大量使用的 palloc,repalloc,pfree 等都是基于 MemoryContext 内存管理机制对动态申请的内存进行管理。
1. MemoryContext 结构
MemoryContext 是一个指向 MemoryContextData 结构体的指针类型。
typedef struct MemoryContextData
{
NodeTag type; /* identifies exact kind of context */
/* these two fields are placed here to minimize alignment wastage: */
bool isReset; /* T = no space alloced since last reset */
bool allowInCritSection; /* allow palloc in critical section */
Size mem_allocated; /* track memory allocated for this context */
const MemoryContextMethods *methods; /* virtual function table */
MemoryContext parent; /* NULL if no parent (toplevel context) */
MemoryContext firstchild; /* head of linked list of children */
MemoryContext prevchild; /* previous child of same parent */
MemoryContext nextchild; /* next child of same parent */
const char *name; /* context name (just for debugging) */
const char *ident; /* context ID if any (just for debugging) */
MemoryContextCallback *reset_cbs; /* list of reset/delete callbacks */
} MemoryContextData;
typedef struct MemoryContextData *MemoryContext;
type 成员变量类型为 NodeTag, 是一个枚举类型,PG 内核中所有 Node 类型,其第一个成员都是 NodeTag。对于内存上下文而言,可取的 NodeTag 主要包括如下几个:
T_MemoryContext,
T_AllocSetContext,
T_SlabContext,
T_GenerationContext,
methods 是 MemoryContext 内存管理的主要函数,主要包括如下函数:
context->methods->alloc()
context->methods->free_p()
context->methods->realloc()
context->methods->reset()
context->methods->delete_context()
context->methods->get_chunk_space()
context->methods->is_empty()
context->methods->stats()
context->methods->check() //debug使用
上述函数指针指向的实际函数如下:
static const MemoryContextMethods AllocSetMethods = {
AllocSetAlloc,
AllocSetFree,
AllocSetRealloc,
AllocSetReset,
AllocSetDelete,
AllocSetGetChunkSpace,
AllocSetIsEmpty,
AllocSetStats
#ifdef MEMORY_CONTEXT_CHECKING
,AllocSetCheck
#endif
};
2. MemoryContext 的初始化
在 postmaster 进程的 main 函数中,调用 MemoryContextInit() 函数进行内存上下文的初始化,该函数主要初始化 2 类 MemoryContext:
- TopMemoryContext
- ErrorContext
TopMemoryContext 是所有其他 MemoryContext 的父节点,初始化时 CurrentMemoryContext 指向 TopMemoryContext,CurrentMemoryContext 会在代码执行过程中动态切换,根据需要换到不同的 MemoryContext 上。
PG 内核中共用 7 个重要的全局 MemoryContext,它们的使用场景通过其变量名基本可以看出来,如下:
MemoryContext TopMemoryContext = NULL;
MemoryContext ErrorContext = NULL;
MemoryContext PostmasterContext = NULL;
MemoryContext CacheMemoryContext = NULL;
MemoryContext MessageContext = NULL;
MemoryContext TopTransactionContext = NULL;
MemoryContext CurTransactionContext = NULL;
CurrentMemoryContext 也是一个全局指针变量,指向当前正在使用的 MemoryContext。
在 MemoryContextInit() 函数内部,MemoryContext 通过调用 AllocSetContextCreate() 进行创建。
3. MemoryContext 相关函数
- 创建 MemoryContext: AllocSetContextCreate()
- 切换 MemoryContext:MemoryContextSwitchTo()
- 删除 MemoryContext:MemoryContextDelete()
- 动态分配内存与释放 palloc、palloc0、repalloc、pfree 都是基于 MemoryContext 进行内存管理,palloc0 申请出来的内存初始化为 0,palloc 则不会对内存设置初始值
- GetMemoryChunkContext(),根据一个内存指针,获取它属于哪个 MemoryContext
- 其他函数,详见 mcxt.c 源文件