/* we want to be sure ErrorContext still has some memory even if we've run out elsewhere! * Don't limit the memory allocation for ErrorContext. And skip memory tracking memory allocation. */ if ((0 != strcmp(name, "ErrorContext")) && (0 != strcmp(name, "MemoryTrackMemoryContext")) && (strcmp(name, "Track MemoryInfo hash") != 0) && (0 != strcmp(name, "DolphinErrorData"))) value |= IS_PROTECT;
/* only track the unshared context after t_thrd.mem_cxt.mem_track_mem_cxt is created */ if (func == &GenericFunctions && parent && (MEMORY_TRACKING_MODE > MEMORY_TRACKING_PEAKMEMORY) && t_thrd.mem_cxt.mem_track_mem_cxt && (t_thrd.utils_cxt.ExecutorMemoryTrack == NULL || ((AllocSet)parent)->track)) { isTracked = true; value |= IS_TRACKED; }
/* Do the type-independent part of context creation */ context = (AllocSet)MemoryContextCreate(type, sizeof(AllocSetContext), parent, name, __FILE__, __LINE__);
if (isShared && maxSize == DEFAULT_MEMORY_CONTEXT_MAX_SIZE) { // default maxSize of shared memory context. context->maxSpaceSize = SHARED_MEMORY_CONTEXT_MAX_SIZE; } else { // set by user (shared or generic),default generic max size(eg. 10M), // these three types run following scope: context->maxSpaceSize = maxSize + SELF_GENRIC_MEMCTX_LIMITATION; } /* * If MemoryContext's name is in white list(GUC parameter,see @memory_context_limited_white_list), * then set maxSize as infinite,that is unlimited. */ #ifdef MEMORY_CONTEXT_CHECKING MemoryContextControlSet(context, name); #endif
/* assign the method function with specified templated to the context */ AllocSetContextSetMethods(value, ((MemoryContext)context)->methods);
/* * Make sure alloc parameters are reasonable, and save them. * * We somewhat arbitrarily enforce a minimum 1K block size. */ initBlockSize = MAXALIGN(initBlockSize); if (initBlockSize < 1024) initBlockSize = 1024; maxBlockSize = MAXALIGN(maxBlockSize); if (maxBlockSize < initBlockSize) maxBlockSize = initBlockSize; context->initBlockSize = initBlockSize; context->maxBlockSize = maxBlockSize; context->nextBlockSize = initBlockSize;
/* create the memory track structure */ if (isTracked) MemoryTrackingCreate((MemoryContext)context, parent);
/* * Compute the allocation chunk size limit for this context. It can't be * more than ALLOC_CHUNK_LIMIT because of the fixed number of freelists. * If maxBlockSize is small then requests exceeding the maxBlockSize, or * even a significant fraction of it, should be treated as large chunks * too. For the typical case of maxBlockSize a power of 2, the chunk size * limit will be at most 1/8th maxBlockSize, so that given a stream of * requests that are all the maximum chunk size we will waste at most * 1/8th of the allocated space. * * We have to have allocChunkLimit a power of two, because the requested * and actually-allocated sizes of any chunk must be on the same side of * the limit, else we get confused about whether the chunk is "big". */ context->allocChunkLimit = ALLOC_CHUNK_LIMIT; while ((Size)(context->allocChunkLimit + ALLOC_CHUNKHDRSZ) > (Size)((maxBlockSize - ALLOC_BLOCKHDRSZ) / ALLOC_CHUNK_FRACTION)) context->allocChunkLimit >>= 1;
/* update the memory tracking information when allocating memory */ if (isTracked) MemoryTrackingAllocInfo((MemoryContext)context, blksize);
block->prev = NULL; block->next = NULL; /* Remember block as part of block list */ context->blocks = block; /* Mark block as not to be released at reset time */ context->keeper = block; }
context->header.is_shared = isShared; if (isShared) (void)pthread_rwlock_init(&(context->header.lock), NULL);
/* Get space for node and name */ if (root != NULL) { /* Normal case: allocate the node in Root MemoryContext */ node = (MemoryContext)MemoryAllocFromContext(root, needed, file, line); } else { /* Special case for startup: use good ol' malloc */ node = (MemoryContext)malloc(needed); if (node == NULL) ereport(ERROR, (errcode(ERRCODE_OUT_OF_MEMORY), errmsg("out of memory"), errdetail("Failed on request of size %lu in %s:%d.", (unsignedlong)needed, file, line))); }
/* * std_MemoryContextDeleteChildren * Delete all the descendants of the named context and release all * space allocated therein. The named context itself is not touched. */ voidstd_MemoryContextDeleteChildren(MemoryContext context, List* context_list) { AssertArg(MemoryContextIsValid(context)); List res_list = {T_List, 0, NULL, NULL}; if (context_list == NULL) { context_list = &res_list; }
if (MemoryContextIsShared(context)) MemoryContextLock(context);
/* * MemoryContextDelete will delink the child from me, so just iterate as * long as there is a child. */ while (context->firstchild != NULL) MemoryContextDeleteInternal(context->firstchild, true, context_list);
if (MemoryContextIsShared(context)) MemoryContextUnlock(context);
if (context_list == &res_list) { FreeMemoryContextList(&res_list); } }
staticvoidMemoryContextDeleteInternal(MemoryContext context, bool parent_locked, List* context_list) { AssertArg(MemoryContextIsValid(context)); /* We had better not be deleting t_thrd.top_mem_cxt ... */ Assert(context != t_thrd.top_mem_cxt); /* And not CurrentMemoryContext, either */ Assert(context != CurrentMemoryContext);
/* * If the parent context is shared and is already locked by the caller, * no need to relock again. In fact, that's not the right thing to do * since it will lead to a self-deadlock */ if (parent && MemoryContextIsShared(parent) && (!parent_locked)) MemoryContextLock(parent); /* * We delink the context from its parent before deleting it, so that if * there's an error we won't have deleted/busted contexts still attached * to the context tree. Better a leak than a crash. */ TopMemCxtUnSeal(); MemoryContextSetParent(context, NULL); if (parent != NULL && MemoryContextIsShared(parent) && (parent_locked == false)) MemoryContextUnlock(parent);
/* * AllocSetDelete * Frees all memory which is allocated in the given set, * in preparation for deletion of the set. * * Unlike AllocSetReset, this *must* free all resources of the set. * But note we are not responsible for deleting the context node itself. */ template <bool enable_memoryprotect, bool is_shared, bool is_tracked> voidGenericMemoryAllocator::AllocSetDelete(MemoryContext context) { AllocSet set = (AllocSet)context; AssertArg(AllocSetIsValid(set));
* This is the virtual function table for Memory Functions */ MemoryProtectFuncDef GenericFunctions = {MemoryProtectFunctions::gs_memprot_malloc<MEM_THRD>, MemoryProtectFunctions::gs_memprot_free<MEM_THRD>, MemoryProtectFunctions::gs_memprot_realloc<MEM_THRD>, MemoryProtectFunctions::gs_posix_memalign<MEM_THRD>};
/* * Memory allocation for sz bytes. If memory quota is enabled, it uses gs_malloc_internal to * reserve the chunk and allocate memory. */ template <MemType mem_type> void* MemoryProtectFunctions::gs_memprot_malloc(Size sz, bool needProtect) { if (!t_thrd.utils_cxt.gs_mp_inited) returnmalloc(sz);
void* ptr = NULL; bool status = memTracker_ReserveMem<mem_type>(sz, needProtect);
if (status == true) { ptr = malloc(sz); //这里分配内存 if (ptr == NULL) { memTracker_ReleaseMem<mem_type>(sz); gs_memprot_failed<false>(sz, mem_type);