typedefstructMemoryContextData{ NodeTag type; /* identifies exact kind of context */ MemoryContextMethods *methods; /* virtual function table */ MemoryContext parent; /* NULL if no parent (toplevel context) */ MemoryContext firstchild; /* head of linked list of children */ MemoryContext nextchild; /* next child of same parent */ char *name; /* context name (just for debugging) */ bool isReset; /* T = no space alloced since last reset */ } MemoryContextData;
typedefstructAllocSetContext{ 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 */ /* 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;
AllocSet set = (AllocSet) context; // MemoryContext context;
AllocBlockData
AllocBlockData 是PG管理内存的基本单位,每次向OS申请都是Block的单位。
1 2 3 4 5 6 7 8
typedefstructAllocBlockData* AllocBlock; typedefstructAllocBlockData{ AllocSet aset; /* aset that owns this block */ AllocBlock prev; /* prev block in aset's blocks list, if any */ AllocBlock next; /* next block in aset's blocks list, if any */ char *freeptr; /* start of free space in this block */ char *endptr; /* end of space in this block */ }AllocBlockData;
/* * Try to detect bogus pointers handed to us, poorly though we can. * Presumably, a pointer that isn't MAXALIGNED isn't pointing at an * allocated chunk. */ Assert(pointer != NULL); Assert(pointer == (void*)MAXALIGN(pointer));
/* * If this is a shared context, make it thread safe by acquiring * appropriate lock */ if (is_shared) { MemoryContextLock(context); func = &SharedFunctions; } else { CHECK_CONTEXT_OWNER(context); if (context->session_id > 0) func = &SessionFunctions; else func = &GenericFunctions; }
AllocFreeInfo(set, chunk);
#ifdef MEMORY_CONTEXT_CHECKING /* Test for someone scribbling on unused space in chunk */ if (chunk->requested_size != (Size)MAXALIGN(chunk->requested_size) && chunk->requested_size < chunk->size) if (!sentinel_ok(pointer, chunk->requested_size - ALLOC_MAGICHDRSZ)) { if (is_shared) { MemoryContextUnlock(context); } ereport(PANIC, (errmsg("detected write past chunk end in %s", set->header.name))); } AllocMagicData* magic = (AllocMagicData*)(((char*)chunk) + ALLOC_CHUNKHDRSZ + MAXALIGN(chunk->requested_size) - ALLOC_MAGICHDRSZ); Assert(magic->aset == set && magic->size == chunk->size && magic->posnum == PosmagicNum); #endif
#ifndef ENABLE_MEMORY_CHECK if (chunk->size > set->allocChunkLimit) { #endif /* * Big chunks are certain to have been allocated as single-chunk * blocks. Find the containing block and return it to malloc(). */ AllocBlock block = (AllocBlock)(((char*)chunk) - ALLOC_BLOCKHDRSZ);
if (is_tracked) MemoryTrackingFreeInfo(context, tempSize);
if (GS_MP_INITED) (*func->free)(block, tempSize); else gs_free(block, tempSize); #ifndef ENABLE_MEMORY_CHECK } else { /* Normal case, put the chunk into appropriate freelist */ int fidx = AllocSetFreeIndex(chunk->size);