pg中的内存是内存上下文来管理的,有不同类型的上下文,不同的上下文是通过MemoryContextMethods指针操作的,下面的是顶层的上下文
MemoryContext CurrentMemoryContext = NULL;默认的上下文
MemoryContext TopMemoryContext = NULL;
MemoryContext ErrorContext = NULL;
MemoryContext PostmasterContext = NULL;
MemoryContext CacheMemoryContext = NULL;
MemoryContext MessageContext = NULL;
MemoryContext TopTransactionContext = NULL;
MemoryContext CurTransactionContext = NULL;
使用The MemoryContextSwitchTo()
operation selects a new current context (and returns the previous context,
so that the caller can restore the previous context before exiting).
能切换到新的上下文中并保留之前的上下文
在postmaster初始化的时候调用MemoryContextInit
* In normal multi-backend operation, this is called once during
* postmaster startup, and not at all by individual backend startup
在入口main函数中使用MemoryContextInit();来创建内存上下文,这个方法会初始化TopMemoryContext and ErrorContext
在MemoryContextInit中使用下马的方法分配上下文
TopMemoryContext = AllocSetContextCreate((MemoryContext) NULL,
“TopMemoryContext”,
0,
8 * 1024,
8 * 1024);
在AllocSetContextCreate中使用MemoryContextCreate创建一个上下文,AlocSet 是一个指向AllocSetContext的指针,这个是实际的返回的上下文,这个方法只是创建了一个节点
context = (AllocSet) MemoryContextCreate(T_AllocSetContext,
sizeof(AllocSetContext),
&AllocSetMethods,
parent,
name);
在创建节点后,然后初始化这个节点的分配参数,比如,初始值,最大值,下一个分配值等。
在MemoryContextCreate中,将返回转成了AllocSet指针
(AllocSet)MemoryContextCreate(NodeTag tag, Size size,
MemoryContextMethods *methods,
MemoryContext parent,
const char *name)
在这个函数中使用node = (MemoryContext) malloc(needed);分配了节点的空间,然后配置了节点的信息主要是添加到上下文二叉树中最左边
if (parent)
{
node->parent = parent;
node->nextchild = parent->firstchild;
parent->firstchild = node;
}
在节点创建完成后,在分配下这个上下文节点的空间
Size blksize = MAXALIGN(minContextSize);
AllocBlock block;
block = (AllocBlock) malloc(blksize);
if (block == NULL)
{
MemoryContextStats(TopMemoryContext);
ereport(ERROR,
(errcode(ERRCODE_OUT_OF_MEMORY),
errmsg("out of memory"),
errdetail("Failed while creating memory context \"%s\".",
name)));
}
block->aset = context;
block->freeptr = ((char *) block) + ALLOC_BLOCKHDRSZ;
block->endptr = ((char *) block) + blksize;
block->next = context->blocks;
context->blocks = block;
/* Mark block as not to be released at reset time */
context->keeper = block;
在之后就可以在这内存上下文中进行内存的分配,回收了,下面是一些相关的数据结构,上下文的内存是通过AllocBlock指针进行链接的。
typedef struct AllocSetContext
{
MemoryContextData header; /* Standard memory-context fields */
/* Info about storage allocated in this context: */
AllocBlock blocks; /* head of list of blocks in this set */
AllocChunk freelist[ALLOCSET_NUM_FREELISTS]; /* free chunk lists */
bool isReset; /* T = no space alloced since last reset */
/* Allocation parameters for this context: */
Size initBlockSize; /* initial block size */
Size maxBlockSize; /* maximum block size */
Size nextBlockSize; /* next block size to allocate */
Size allocChunkLimit; /* effective chunk size limit */
AllocBlock keeper; /* if not NULL, keep this block over resets */
} AllocSetContext;
上面的blocks是一个指向所有内存链表开始的指针,freelist是空闲内存数组,这里面说是每个元素保存了一定尺寸大小空闲内存,这个跟oracle差不多,为了能分配给请求合适大小的内存,提高分配效率。具体代码没看到,待需要在看
typedef AllocSetContext *AllocSet;
typedef struct AllocBlockData *AllocBlock;
typedef struct AllocChunkData *AllocChunk;
struct AllocBlockData
{
AllocSet aset; /* aset that owns this block */
AllocBlock next; /* next block in aset’s blocks list */
char freeptr; / start of free space in this block */
char endptr; / end of space in this block */
} AllocBlockData;
在main中分配了顶层的内存上下文,到postmaster中,我们看到使用了下面的方式分配postmaster的内存上下文
PostmasterContext = AllocSetContextCreate(TopMemoryContext,
“Postmaster”,
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE);
父指向了TopMemoryContext