PostgreSQL 内存上下文 MemoryContext

2023年 8月 15日 72.1k 0

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

相关文章

Oracle如何使用授予和撤销权限的语法和示例
Awesome Project: 探索 MatrixOrigin 云原生分布式数据库
下载丨66页PDF,云和恩墨技术通讯(2024年7月刊)
社区版oceanbase安装
Oracle 导出CSV工具-sqluldr2
ETL数据集成丨快速将MySQL数据迁移至Doris数据库

发布评论