aset.c
来自「postgresql8.3.4源码,开源数据库」· C语言 代码 · 共 1,129 行 · 第 1/3 页
C
1,129 行
/* * AllocSetInit * Context-type-specific initialization routine. * * This is called by MemoryContextCreate() after setting up the * generic MemoryContext fields and before linking the new context * into the context tree. We must do whatever is needed to make the * new context minimally valid for deletion. We must *not* risk * failure --- thus, for example, allocating more memory is not cool. * (AllocSetContextCreate can allocate memory when it gets control * back, however.) */static voidAllocSetInit(MemoryContext context){ /* * Since MemoryContextCreate already zeroed the context node, we don't * have to do anything here: it's already OK. */}/* * AllocSetReset * Frees all memory which is allocated in the given set. * * Actually, this routine has some discretion about what to do. * It should mark all allocated chunks freed, but it need not necessarily * give back all the resources the set owns. Our actual implementation is * that we hang onto any "keeper" block specified for the set. In this way, * we don't thrash malloc() when a context is repeatedly reset after small * allocations, which is typical behavior for per-tuple contexts. */static voidAllocSetReset(MemoryContext context){ AllocSet set = (AllocSet) context; AllocBlock block; AssertArg(AllocSetIsValid(set)); /* Nothing to do if no pallocs since startup or last reset */ if (set->isReset) return;#ifdef MEMORY_CONTEXT_CHECKING /* Check for corruption and leaks before freeing */ AllocSetCheck(context);#endif /* Clear chunk freelists */ MemSetAligned(set->freelist, 0, sizeof(set->freelist)); block = set->blocks; /* New blocks list is either empty or just the keeper block */ set->blocks = set->keeper; while (block != NULL) { AllocBlock next = block->next; if (block == set->keeper) { /* Reset the block, but don't return it to malloc */ char *datastart = ((char *) block) + ALLOC_BLOCKHDRSZ;#ifdef CLOBBER_FREED_MEMORY /* Wipe freed memory for debugging purposes */ memset(datastart, 0x7F, block->freeptr - datastart);#endif block->freeptr = datastart; block->next = NULL; } else { /* Normal case, release the block */#ifdef CLOBBER_FREED_MEMORY /* Wipe freed memory for debugging purposes */ memset(block, 0x7F, block->freeptr - ((char *) block));#endif free(block); } block = next; } /* Reset block size allocation sequence, too */ set->nextBlockSize = set->initBlockSize; set->isReset = true;}/* * 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. */static voidAllocSetDelete(MemoryContext context){ AllocSet set = (AllocSet) context; AllocBlock block = set->blocks; AssertArg(AllocSetIsValid(set));#ifdef MEMORY_CONTEXT_CHECKING /* Check for corruption and leaks before freeing */ AllocSetCheck(context);#endif /* Make it look empty, just in case... */ MemSetAligned(set->freelist, 0, sizeof(set->freelist)); set->blocks = NULL; set->keeper = NULL; while (block != NULL) { AllocBlock next = block->next;#ifdef CLOBBER_FREED_MEMORY /* Wipe freed memory for debugging purposes */ memset(block, 0x7F, block->freeptr - ((char *) block));#endif free(block); block = next; }}/* * AllocSetAlloc * Returns pointer to allocated memory of given size; memory is added * to the set. */static void *AllocSetAlloc(MemoryContext context, Size size){ AllocSet set = (AllocSet) context; AllocBlock block; AllocChunk chunk; int fidx; Size chunk_size; Size blksize; AssertArg(AllocSetIsValid(set)); /* * If requested size exceeds maximum for chunks, allocate an entire block * for this request. */ if (size > set->allocChunkLimit) { chunk_size = MAXALIGN(size); blksize = chunk_size + ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ; block = (AllocBlock) malloc(blksize); if (block == NULL) { MemoryContextStats(TopMemoryContext); ereport(ERROR, (errcode(ERRCODE_OUT_OF_MEMORY), errmsg("out of memory"), errdetail("Failed on request of size %lu.", (unsigned long) size))); } block->aset = set; block->freeptr = block->endptr = ((char *) block) + blksize; chunk = (AllocChunk) (((char *) block) + ALLOC_BLOCKHDRSZ); chunk->aset = set; chunk->size = chunk_size;#ifdef MEMORY_CONTEXT_CHECKING chunk->requested_size = size; /* set mark to catch clobber of "unused" space */ if (size < chunk_size) ((char *) AllocChunkGetPointer(chunk))[size] = 0x7E;#endif /* * Stick the new block underneath the active allocation block, so that * we don't lose the use of the space remaining therein. */ if (set->blocks != NULL) { block->next = set->blocks->next; set->blocks->next = block; } else { block->next = NULL; set->blocks = block; } set->isReset = false; AllocAllocInfo(set, chunk); return AllocChunkGetPointer(chunk); } /* * Request is small enough to be treated as a chunk. Look in the * corresponding free list to see if there is a free chunk we could reuse. * If one is found, remove it from the free list, make it again a member * of the alloc set and return its data address. */ fidx = AllocSetFreeIndex(size); chunk = set->freelist[fidx]; if (chunk != NULL) { Assert(chunk->size >= size); set->freelist[fidx] = (AllocChunk) chunk->aset; chunk->aset = (void *) set;#ifdef MEMORY_CONTEXT_CHECKING chunk->requested_size = size; /* set mark to catch clobber of "unused" space */ if (size < chunk->size) ((char *) AllocChunkGetPointer(chunk))[size] = 0x7E;#endif /* isReset must be false already */ Assert(!set->isReset); AllocAllocInfo(set, chunk); return AllocChunkGetPointer(chunk); } /* * Choose the actual chunk size to allocate. */ chunk_size = (1 << ALLOC_MINBITS) << fidx; Assert(chunk_size >= size); /* * If there is enough room in the active allocation block, we will put the * chunk into that block. Else must start a new one. */ if ((block = set->blocks) != NULL) { Size availspace = block->endptr - block->freeptr; if (availspace < (chunk_size + ALLOC_CHUNKHDRSZ)) { /* * The existing active (top) block does not have enough room for * the requested allocation, but it might still have a useful * amount of space in it. Once we push it down in the block list, * we'll never try to allocate more space from it. So, before we * do that, carve up its free space into chunks that we can put on * the set's freelists. * * Because we can only get here when there's less than * ALLOC_CHUNK_LIMIT left in the block, this loop cannot iterate * more than ALLOCSET_NUM_FREELISTS-1 times. */ while (availspace >= ((1 << ALLOC_MINBITS) + ALLOC_CHUNKHDRSZ)) { Size availchunk = availspace - ALLOC_CHUNKHDRSZ; int a_fidx = AllocSetFreeIndex(availchunk); /* * In most cases, we'll get back the index of the next larger * freelist than the one we need to put this chunk on. The * exception is when availchunk is exactly a power of 2. */ if (availchunk != (1 << (a_fidx + ALLOC_MINBITS))) { a_fidx--; Assert(a_fidx >= 0); availchunk = (1 << (a_fidx + ALLOC_MINBITS)); } chunk = (AllocChunk) (block->freeptr); block->freeptr += (availchunk + ALLOC_CHUNKHDRSZ); availspace -= (availchunk + ALLOC_CHUNKHDRSZ); chunk->size = availchunk;#ifdef MEMORY_CONTEXT_CHECKING chunk->requested_size = 0; /* mark it free */#endif chunk->aset = (void *) set->freelist[a_fidx]; set->freelist[a_fidx] = chunk; } /* Mark that we need to create a new block */ block = NULL; } } /* * Time to create a new regular (multi-chunk) block? */ if (block == NULL) { Size required_size; /* * The first such block has size initBlockSize, and we double the * space in each succeeding block, but not more than maxBlockSize. */ blksize = set->nextBlockSize; set->nextBlockSize <<= 1; if (set->nextBlockSize > set->maxBlockSize) set->nextBlockSize = set->maxBlockSize; /* * If initBlockSize is less than ALLOC_CHUNK_LIMIT, we could need more * space... but try to keep it a power of 2. */ required_size = chunk_size + ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ; while (blksize < required_size) blksize <<= 1; /* Try to allocate it */ block = (AllocBlock) malloc(blksize); /* * We could be asking for pretty big blocks here, so cope if malloc * fails. But give up if there's less than a meg or so available... */ while (block == NULL && blksize > 1024 * 1024) { blksize >>= 1; if (blksize < required_size) break; block = (AllocBlock) malloc(blksize); } if (block == NULL) { MemoryContextStats(TopMemoryContext); ereport(ERROR, (errcode(ERRCODE_OUT_OF_MEMORY), errmsg("out of memory"), errdetail("Failed on request of size %lu.", (unsigned long) size))); } block->aset = set; block->freeptr = ((char *) block) + ALLOC_BLOCKHDRSZ; block->endptr = ((char *) block) + blksize; /* * If this is the first block of the set, make it the "keeper" block. * Formerly, a keeper block could only be created during context * creation, but allowing it to happen here lets us have fast reset * cycling even for contexts created with minContextSize = 0; that way * we don't have to force space to be allocated in contexts that might * never need any space. Don't mark an oversize block as a keeper, * however. */ if (set->keeper == NULL && blksize == set->initBlockSize) set->keeper = block; block->next = set->blocks; set->blocks = block; } /* * OK, do the allocation */ chunk = (AllocChunk) (block->freeptr); block->freeptr += (chunk_size + ALLOC_CHUNKHDRSZ); Assert(block->freeptr <= block->endptr); chunk->aset = (void *) set; chunk->size = chunk_size;#ifdef MEMORY_CONTEXT_CHECKING chunk->requested_size = size; /* set mark to catch clobber of "unused" space */ if (size < chunk->size) ((char *) AllocChunkGetPointer(chunk))[size] = 0x7E;#endif
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?