postgres-內存上下文分配源碼

AtStart_Memory();

--//xact.c

/*
*      AtStart_Memory
*/
static void
AtStart_Memory(void)
{
        TransactionState s = CurrentTransactionState;

        /*
        * If this is the first time through, create a private context for
        * AbortTransaction to work in.  By reserving some space now, we can
        * insulate AbortTransaction from out-of-memory scenarios.  Like
        * ErrorContext, we set it up with slow growth rate and a nonzero minimum
        * size, so that space will be reserved immediately.
        */
        if (TransactionAbortContext == NULL)
                TransactionAbortContext =
                        AllocSetContextCreate(TopMemoryContext,
                                                                  "TransactionAbortContext",
                                                                  32 * 1024,
                                                                  32 * 1024,
                                                                  32 * 1024);

        /*
        * We shouldn't have a transaction context already.
        */
        Assert(TopTransactionContext == NULL);

        /*
        * Create a toplevel context for the transaction.
        */
        TopTransactionContext =
                AllocSetContextCreate(TopMemoryContext,
                                                          "TopTransactionContext",
                                                          ALLOCSET_DEFAULT_SIZES);

        /*
        * In a top-level transaction, CurTransactionContext is the same as
        * TopTransactionContext.
        */
        CurTransactionContext = TopTransactionContext;
        s->curTransactionContext = CurTransactionContext;

        /* Make the CurTransactionContext active. */
        MemoryContextSwitchTo(CurTransactionContext);
}

--//在AtStart_Memory裏面包含了TransactionAbortContext、TopTransactionContext的創建以及MemoryContextSwitchTo的調用。
這裏主要分爲三點來說
①、其中TopTransactionContext傳入的參數包含宏定義ALLOCSET_DEFAULT_SIZES。
②、AllocSetContextCreate函數調用中的第一個參數TopMemoryContext
③、TransactionAbortContext、TopTransactionContext的創建都是調用AllocSetContextCreate函數,只是傳入的參數不一樣。

--//先解釋第一點①


--//TopTransactionContext創建時的ALLOCSET_DEFAULT_SIZES參數包含在頭文件memutils.h中,定義如下:

/*
 * Recommended default alloc parameters, suitable for "ordinary" contexts
 * that might hold quite a lot of data.
 */
#define ALLOCSET_DEFAULT_MINSIZE   0
#define ALLOCSET_DEFAULT_INITSIZE  (8 * 1024)
#define ALLOCSET_DEFAULT_MAXSIZE   (8 * 1024 * 1024)
#define ALLOCSET_DEFAULT_SIZES \
        ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE

--//先解釋第一點②
--//頭文件mcxt.c

 /*****************************************************************************
 *        GLOBAL MEMORY                                                                                                                  *
 *****************************************************************************/

/*
 * CurrentMemoryContext
 *              Default memory context for allocations.
 */
MemoryContext CurrentMemoryContext = NULL;

 
 * contexts.  TopMemoryContext and ErrorContext are initialized here;
 * other contexts must be created afterwards.
 *
 * In normal multi-backend operation, this is called once during
 * postmaster startup, and not at all by individual backend startup
 * (since the backends inherit an already-initialized context subsystem
 * by virtue of being forked off the postmaster).  But in an EXEC_BACKEND
 * build, each process must do this for itself.
 *
 * In a standalone backend this must be called during backend startup.
 */
void
MemoryContextInit(void)
{
        AssertState(TopMemoryContext == NULL);

        /*
         * First, initialize TopMemoryContext, which is the parent of all others.
         */
        TopMemoryContext = AllocSetContextCreate((MemoryContext) NULL,
                                                                                         "TopMemoryContext",
                                                                                         ALLOCSET_DEFAULT_SIZES);

        /*
         * Not having any other place to point CurrentMemoryContext, make it point
         * to TopMemoryContext.  Caller should change this soon!
         */
        CurrentMemoryContext = TopMemoryContext;

        /*
         * Initialize ErrorContext as an AllocSetContext with slow growth rate ---
         * we don't really expect much to be allocated in it. More to the point,
         * require it to contain at least 8K at all times. This is the only case
         * where retained memory in a context is *essential* --- we want to be
         * sure ErrorContext still has some memory even if we've run out
         * elsewhere! Also, allow allocations in ErrorContext within a critical
         * section. Otherwise a PANIC will cause an assertion failure in the error
         * reporting code, before printing out the real cause of the failure.
         *
         * This should be the last step in this function, as elog.c assumes memory
         * management works once ErrorContext is non-null.
         */
        ErrorContext = AllocSetContextCreate(TopMemoryContext,
                                                                                 "ErrorContext",
                                                                                 8 * 1024,
                                                                                 8 * 1024,
                                                                                 8 * 1024);
        MemoryContextAllowInCriticalSection(ErrorContext, true);
}

--//MemoryContextInit函數包含TopMemoryContext、ErrorContext的初始化,CurrentMemoryContext定義爲NULL,TopMemoryContext的初始化參數定義爲ALLOCSET_DEFAULT_SIZES。該參數的定義爲見上面解釋的第一點

--//解釋第三點
--//查看AllocSetContextCreate的定義,定義在頭文件memutils.h

--//AllocSetContextCreate被定義爲AllocSetContextCreateExtended
--//AllocSetContextCreateExtended的定義如下
/*
 * Memory-context-type-specific functions
 */

/* aset.c */
extern MemoryContext AllocSetContextCreateExtended(MemoryContext parent,
                                                          const char *name,
                                                          Size minContextSize,
                                                          Size initBlockSize,
                                                          Size maxBlockSize);

--//AllocSetContextCreateExtended的函數定義,函數實現在頭文件aset.c

/*
 * AllocSetContextCreateExtended
 *              Create a new AllocSet context.
 *
 * parent: parent context, or NULL if top-level context
 * name: name of context (must be statically allocated)
 * minContextSize: minimum context size
 * initBlockSize: initial allocation block size
 * maxBlockSize: maximum allocation block size
 *
 * Most callers should abstract the context size parameters using a macro
 * such as ALLOCSET_DEFAULT_SIZES.
 *
 * Note: don't call this directly; go through the wrapper macro
 * AllocSetContextCreate.
 */
MemoryContext
AllocSetContextCreateExtended(MemoryContext parent,
                                                          const char *name,
                                                          Size minContextSize,
                                                          Size initBlockSize,
                                                          Size maxBlockSize)
{
        int             freeListIndex;
        Size            firstBlockSize;
        AllocSet        set;        //--④、AllocSet的定義
        AllocBlock      block;      //--⑤、AllocBlock的定義

        /* Assert we padded AllocChunkData properly */
        StaticAssertStmt(ALLOC_CHUNKHDRSZ == MAXALIGN(ALLOC_CHUNKHDRSZ),
                                         "sizeof(AllocChunkData) is not maxaligned");
        StaticAssertStmt(offsetof(AllocChunkData, aset) + sizeof(MemoryContext) ==
                                         ALLOC_CHUNKHDRSZ,
                                         "padding calculation in AllocChunkData is wrong");

        /*
         * First, validate allocation parameters.  Once these were regular runtime
         * test and elog's, but in practice Asserts seem sufficient because nobody
         * varies their parameters at runtime.  We somewhat arbitrarily enforce a
         * minimum 1K block size.
         */
        //--⑥、Assert斷言的一些使用,主要判斷出入的參數是否滿足條件
        Assert(initBlockSize == (initBlockSize) &&
                   initBlockSize >= 1024);
        Assert(maxBlockSize == MAXALIGN(maxBlockSize) &&
                   maxBlockSize >= initBlockSize &&
                   AllocHugeSizeIsValid(maxBlockSize)); /* must be safe to double */
        Assert(minContextSize == 0 ||
                   (minContextSize == MAXALIGN(minContextSize) &&
                        minContextSize >= 1024 &&
                        minContextSize <= maxBlockSize));

        /*
         * Check whether the parameters match either available freelist.  We do
         * not need to demand a match of maxBlockSize.
         */
        //--⑦、根據傳入值判檢查參數是否匹配可用的空閒列表
        if (minContextSize == ALLOCSET_DEFAULT_MINSIZE &&
                initBlockSize == ALLOCSET_DEFAULT_INITSIZE)
                freeListIndex = 0;
        else if (minContextSize == ALLOCSET_SMALL_MINSIZE &&
                         initBlockSize == ALLOCSET_SMALL_INITSIZE)
                freeListIndex = 1;
        else
                freeListIndex = -1;

        /*
         * If a suitable freelist entry exists, just recycle that context.
         * 如果存在合適的freelist條目,只需回收該上下文
         */
        
        if (freeListIndex >= 0)
        {
                AllocSetFreeList *freelist = &context_freelists[freeListIndex];

                if (freelist->first_free != NULL)
                {
                        /* Remove entry from freelist */
                        set = freelist->first_free;
                        freelist->first_free = (AllocSet) set->header.nextchild;
                        freelist->num_free--;

                        /* Update its maxBlockSize; everything else should be OK */
                        set->maxBlockSize = maxBlockSize;

                        /* Reinitialize its header, installing correct name and parent */
                        MemoryContextCreate((MemoryContext) set,
                                                                T_AllocSetContext,
                                                                &AllocSetMethods,
                                                                parent,
                                                                name);

                        return (MemoryContext) set;
                }
        }

        /* Determine size of initial block */
        //--⑧、決定初始化塊大小
        firstBlockSize = MAXALIGN(sizeof(AllocSetContext)) +
                ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ;
        if (minContextSize != 0)
                firstBlockSize = Max(firstBlockSize, minContextSize);
        else
                firstBlockSize = Max(firstBlockSize, initBlockSize);

        /*
         * Allocate the initial block.  Unlike other aset.c blocks, it starts with
         * the context header and its block header follows that.
         */
        //--⑨、分配firstBlockSize內存空間
        set = (AllocSet) malloc(firstBlockSize);
        if (set == NULL)
        {
                if (TopMemoryContext)
                        MemoryContextStats(TopMemoryContext);
                ereport(ERROR,
                                (errcode(ERRCODE_OUT_OF_MEMORY),
                                 errmsg("out of memory"),
                                 errdetail("Failed while creating memory context \"%s\".",
                                                   name)));
        }

        /*
         * Avoid writing code that can fail between here and MemoryContextCreate;
         * we'd leak the header/initial block if we ereport in this stretch.
         */

        /* Fill in the initial block's block header */
        //--⑩、填充初始塊的塊頭,block是AllocBlock類型的
        block = (AllocBlock) (((char *) set) + MAXALIGN(sizeof(AllocSetContext)));
        block->aset = set;
        block->freeptr = ((char *) block) + ALLOC_BLOCKHDRSZ;
        block->endptr = ((char *) set) + firstBlockSize;
        block->prev = NULL;
        block->next = NULL;

        /* Mark unallocated space NOACCESS; leave the block header alone. */
        VALGRIND_MAKE_MEM_NOACCESS(block->freeptr, block->endptr - block->freeptr);

        /* Remember block as part of block list */
        set->blocks = block;
        /* Mark block as not to be released at reset time */
        set->keeper = block;

        /* Finish filling in aset-specific parts of the context header */
        MemSetAligned(set->freelist, 0, sizeof(set->freelist));

        set->initBlockSize = initBlockSize;
        set->maxBlockSize = maxBlockSize;
        set->nextBlockSize = initBlockSize;
        set->freeListIndex = freeListIndex;

        /*
         * 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".
         *
         * Also, allocChunkLimit must not exceed ALLOCSET_SEPARATE_THRESHOLD.
         */
        StaticAssertStmt(ALLOC_CHUNK_LIMIT == ALLOCSET_SEPARATE_THRESHOLD,
                                         "ALLOC_CHUNK_LIMIT != ALLOCSET_SEPARATE_THRESHOLD");

        set->allocChunkLimit = ALLOC_CHUNK_LIMIT;
        while ((Size) (set->allocChunkLimit + ALLOC_CHUNKHDRSZ) >
                   (Size) ((maxBlockSize - ALLOC_BLOCKHDRSZ) / ALLOC_CHUNK_FRACTION))
                set->allocChunkLimit >>= 1;

        /* Finally, do the type-independent part of context creation */
        //--11)調用MemoryContextCreate函數
        MemoryContextCreate((MemoryContext) set,
                                                T_AllocSetContext,
                                                &AllocSetMethods,
                                                parent,
                                                name);

        return (MemoryContext) set;
}

--//④點AllocSet爲一個AllocSetContext類型結構體指針

/*
 * AllocSetContext is our standard implementation of MemoryContext.
 *
 * Note: header.isReset means there is nothing for AllocSetReset to do.
 * This is different from the aset being physically empty (empty blocks list)
 * because we will still have a keeper block.  It's also different from the set
 * being logically empty, because we don't attempt to detect pfree'ing the
 * last active chunk.
 */
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 */
        /* 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;                 /* keep this block over resets */
        /* freelist this context could be put in, or -1 if not a candidate: */
        int                     freeListIndex;  /* index in context_freelists[], or -1 */
} AllocSetContext;

typedef AllocSetContext *AllocSet;

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 */
        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;
/*
 * Type MemoryContextData is declared in nodes/memnodes.h.  Most users
 * of memory allocation should just treat it as an abstract type, so we
 * do not provide the struct contents here.
 */
typedef struct MemoryContextData *MemoryContext;

typedef struct MemoryContextMethods
{
        void       *(*alloc) (MemoryContext context, Size size);
        /* call this free_p in case someone #define's free() */
        void            (*free_p) (MemoryContext context, void *pointer);
        void       *(*realloc) (MemoryContext context, void *pointer, Size size);
        void            (*reset) (MemoryContext context);
        void            (*delete_context) (MemoryContext context);
        Size            (*get_chunk_space) (MemoryContext context, void *pointer);
        bool            (*is_empty) (MemoryContext context);
        void            (*stats) (MemoryContext context,
                                                  MemoryStatsPrintFunc printfunc, void *passthru,
                                                  MemoryContextCounters *totals);
#ifdef MEMORY_CONTEXT_CHECKING
        void            (*check) (MemoryContext context);
#endif
} MemoryContextMethods;

--//⑤AllocBlock的定義爲AllocBlockData類型的結構體指針

/*
 * AllocBlock
 *              An AllocBlock is the unit of memory that is obtained by aset.c
 *              from malloc().  It contains one or more AllocChunks, which are
 *              the units requested by palloc() and freed by pfree().  AllocChunks
 *              cannot be returned to malloc() individually, instead they are put
 *              on freelists by pfree() and re-used by the next palloc() that has
 *              a matching request size.
 *
 *              AllocBlockData is the header data for a block --- the usable space
 *              within the block begins at the next alignment boundary.
 */
typedef struct AllocBlockData
{
        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;


typedef struct AllocBlockData *AllocBlock;      /* forward reference */

//--⑥、Assert斷言的一些使用,主要判斷出入的參數是否滿足條件

        Assert(initBlockSize == (initBlockSize) &&
                   initBlockSize >= 1024);
        Assert(maxBlockSize == MAXALIGN(maxBlockSize) &&
                   maxBlockSize >= initBlockSize &&
                   AllocHugeSizeIsValid(maxBlockSize)); /* must be safe to double */
        Assert(minContextSize == 0 ||
                   (minContextSize == MAXALIGN(minContextSize) &&
                        minContextSize >= 1024 &&
                        minContextSize <= maxBlockSize));

//--⑦、根據傳入值判檢查參數是否匹配可用的空閒列表

//--⑧、決定初始化塊大小

/* Determine size of initial block */
         firstBlockSize = MAXALIGN(sizeof(AllocSetContext)) +
                ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ;
        if (minContextSize != 0)
                firstBlockSize = Max(firstBlockSize, minContextSize);
        else
                firstBlockSize = Max(firstBlockSize, initBlockSize);

//--⑨、分配firstBlockSize內存空間

        set = (AllocSet) malloc(firstBlockSize);
        if (set == NULL)
        {
                if (TopMemoryContext)
                        MemoryContextStats(TopMemoryContext);
                ereport(ERROR,
                                (errcode(ERRCODE_OUT_OF_MEMORY),
                                 errmsg("out of memory"),
                                 errdetail("Failed while creating memory context \"%s\".",
                                                   name)));
        }

--//根據第⑧計算的初始化塊大小(firstBlockSize)向操作系統申請空間,並把空間類型轉換爲AllocSet。如果申請到的大小爲NULL說明沒有足夠的內存了。

//--⑩、填充初始塊的塊頭,block是AllocBlock類型的

/* Fill in the initial block's block header */
 block = (AllocBlock) (((char *) set) + MAXALIGN(sizeof(AllocSetContext)));
        block->aset = set;        
        block->freeptr = ((char *) block) + ALLOC_BLOCKHDRSZ;
        block->endptr = ((char *) set) + firstBlockSize;
        block->prev = NULL;
        block->next = NULL;

        /* Mark unallocated space NOACCESS; leave the block header alone. */
        VALGRIND_MAKE_MEM_NOACCESS(block->freeptr, block->endptr - block->freeptr);

        /* Remember block as part of block list */
        set->blocks = block;
        /* Mark block as not to be released at reset time */
        set->keeper = block;

        /* Finish filling in aset-specific parts of the context header */
        MemSetAligned(set->freelist, 0, sizeof(set->freelist));

        set->initBlockSize = initBlockSize;
        set->maxBlockSize = maxBlockSize;
        set->nextBlockSize = initBlockSize;
        set->freeListIndex = freeListIndex;

--//block->aset = set;擁有這個區塊的aset(AllocSet),下面設置塊的freeptr,endptr, prev上一個塊, next下一個塊。把這些設置完之後賦值給set->blocks相當於給了AllocSetContext結構體(第⑨步已經根據該AllocSetContext分配了內存空間)中的AllocBlock blocks。 然後初始化set的初始塊大小等。

--//AllocSetContext結構體的定義


/*
 * AllocSetContext is our standard implementation of MemoryContext.
 *
 * Note: header.isReset means there is nothing for AllocSetReset to do.
 * This is different from the aset being physically empty (empty blocks list)
 * because we will still have a keeper block.  It's also different from the set
 * being logically empty, because we don't attempt to detect pfree'ing the
 * last active chunk.
 */
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 */
        /* 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;                 /* keep this block over resets */
        /* freelist this context could be put in, or -1 if not a candidate: */
        int                     freeListIndex;  /* index in context_freelists[], or -1 */
} AllocSetContext;

typedef AllocSetContext *AllocSet;

--//AllocBlockData結構體的定義

/*
 * AllocBlock
 *              An AllocBlock is the unit of memory that is obtained by aset.c
 *              from malloc().  It contains one or more AllocChunks, which are
 *              the units requested by palloc() and freed by pfree().  AllocChunks
 *              cannot be returned to malloc() individually, instead they are put
 *              on freelists by pfree() and re-used by the next palloc() that has
 *              a matching request size.
 *
 *              AllocBlockData is the header data for a block --- the usable space
 *              within the block begins at the next alignment boundary.
 */
typedef struct AllocBlockData
{
        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;


typedef struct AllocBlockData *AllocBlock;      /* forward reference */

--//11)最後調用MemoryContextCreate函數來創建上面定義的context

/* Finally, do the type-independent part of context creation */
     MemoryContextCreate((MemoryContext) set,
                                                T_AllocSetContext,
                                                &AllocSetMethods,
                                                parent,
                                                name);

--//其中第一個參數set就是上面幾步初始化之後的AllocSet類型空間
--//查看MemoryContextCreate函數的定義

/*
 * MemoryContextCreate
 *              Context-type-independent part of context creation.
 *
 * This is only intended to be called by context-type-specific
 * context creation routines, not by the unwashed masses.
 *
 * The memory context creation procedure goes like this:
 *      1.  Context-type-specific routine makes some initial space allocation,
 *              including enough space for the context header.  If it fails,
 *              it can ereport() with no damage done.
 *      2.      Context-type-specific routine sets up all type-specific fields of
 *              the header (those beyond MemoryContextData proper), as well as any
 *              other management fields it needs to have a fully valid context.
 *              Usually, failure in this step is impossible, but if it's possible
 *              the initial space allocation should be freed before ereport'ing.
 *      3.      Context-type-specific routine calls MemoryContextCreate() to fill in
 *              the generic header fields and link the context into the context tree.
 *      4.  We return to the context-type-specific routine, which finishes
 *              up type-specific initialization.  This routine can now do things
 *              that might fail (like allocate more memory), so long as it's
 *              sure the node is left in a state that delete will handle.
 *
 * node: the as-yet-uninitialized common part of the context header node.
 * tag: NodeTag code identifying the memory context type.
 * methods: context-type-specific methods (usually statically allocated).
 * parent: parent context, or NULL if this will be a top-level context.
 * name: name of context (must be statically allocated).
 *
 * Context routines generally assume that MemoryContextCreate can't fail,
 * so this can contain Assert but not elog/ereport.
 */
void
MemoryContextCreate(MemoryContext node,
                                        NodeTag tag,
                                        const MemoryContextMethods *methods,
                                        MemoryContext parent,
                                        const char *name)
{
        /* Creating new memory contexts is not allowed in a critical section */
        Assert(CritSectionCount == 0);

        /* Initialize all standard fields of memory context header */
        node->type = tag;
        node->isReset = true;
        node->methods = methods;
        node->parent = parent;
        node->firstchild = NULL;
        node->prevchild = NULL;
        node->name = name;
        node->ident = NULL;
        node->reset_cbs = NULL;

        /* OK to link node into context tree */
        if (parent)
        {
                node->nextchild = parent->firstchild;
                if (parent->firstchild != NULL)
                        parent->firstchild->prevchild = node;
                parent->firstchild = node;
                /* inherit allowInCritSection flag from parent */
                node->allowInCritSection = parent->allowInCritSection;
        }
        else
        {
                node->nextchild = NULL;
                node->allowInCritSection = false;
        }

        VALGRIND_CREATE_MEMPOOL(node, 0, false);
}

--//parent其實就是最AllocSetContextCreate中傳入的TopMemoryContext。
--//node->nextchild = parent->firstchild;說明是第一塊內存區域
--//
                if (parent->firstchild != NULL)
                        parent->firstchild->prevchild = node;
--//意思就是如果父節點的firstchild不爲空,就把node賦值給父節點的第一個memorycontext的上一個memorycontext。
--//parent->firstchild = node;父節點的第一個memorycontext也被賦值了node。相當於鏈表的頭。

--//下面是自己理解的一個圖

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章