PostgreSQL 内存上下文 MemoryContext

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 源文件

文章评论

0条评论