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 + -
显示快捷键?