📄 aset.c
字号:
*/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; } 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; AllocChunk priorfree; 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 > ALLOC_CHUNK_LIMIT) { 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. */ fidx = AllocSetFreeIndex(size); priorfree = NULL; for (chunk = set->freelist[fidx]; chunk; chunk = (AllocChunk) chunk->aset) { if (chunk->size >= size) break; priorfree = chunk; } /* * If one is found, remove it from the free list, make it again a member * of the alloc set and return its data address. */ if (chunk != NULL) { if (priorfree == NULL) set->freelist[fidx] = (AllocChunk) chunk->aset; else priorfree->aset = 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 << (fidx + ALLOC_MINBITS); 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; if (set->blocks == NULL) { /* First block of the alloc set, use initBlockSize */ blksize = set->initBlockSize; } else { /* * Use first power of 2 that is larger than previous block, but * not more than the allowed limit. (We don't simply double the * prior block size, because in some cases this could be a funny * size, eg if very first allocation was for an odd-sized large * chunk.) */ Size pblksize = set->blocks->endptr - ((char *) set->blocks); blksize = set->initBlockSize; while (blksize <= pblksize) blksize <<= 1; if (blksize > set->maxBlockSize) blksize = 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->blocks == NULL && blksize == set->initBlockSize) { Assert(set->keeper == NULL); 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 set->isReset = false; AllocAllocInfo(set, chunk); return AllocChunkGetPointer(chunk);}/* * AllocSetFree * Frees allocated memory; memory is removed from the set. */static voidAllocSetFree(MemoryContext context, void *pointer){ AllocSet set = (AllocSet) context; AllocChunk chunk = AllocPointerGetChunk(pointer); AllocFreeInfo(set, chunk);#ifdef MEMORY_CONTEXT_CHECKING
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -