src/backend/utils/mmgr/slab.c
static void
SlabFree(MemoryContext context, void *pointer)
{
	int			idx;
	SlabContext *slab = castNode(SlabContext, context);
	SlabChunk  *chunk = SlabPointerGetChunk(pointer);
	SlabBlock  *block = chunk->block;

#ifdef MEMORY_CONTEXT_CHECKING
	/* Test for someone scribbling on unused space in chunk */
	if (slab->chunkSize < (slab->fullChunkSize - sizeof(SlabChunk)))
		if (!sentinel_ok(pointer, slab->chunkSize))
			elog(WARNING, "detected write past chunk end in %s %p",
				 slab->header.name, chunk);
#endif

	/* compute index of the chunk with respect to block start */
	idx = SlabChunkIndex(slab, block, chunk);

	/* add chunk to freelist, and update block nfree count */
	*(int32 *) pointer = block->firstFreeChunk;
	block->firstFreeChunk = idx;
	block->nfree++;

	Assert(block->nfree > 0);
	Assert(block->nfree <= slab->chunksPerBlock);

#ifdef CLOBBER_FREED_MEMORY
	/* XXX don't wipe the int32 index, used for block-level freelist */
	wipe_mem((char *) pointer + sizeof(int32),
			 slab->chunkSize - sizeof(int32));
#endif

	/* remove the block from a freelist */
	dlist_delete(&block->node);

	/*
	 * See if we need to update the minFreeChunks field for the slab - we only
	 * need to do that if there the block had that number of free chunks
	 * before we freed one. In that case, we check if there still are blocks
	 * in the original freelist and we either keep the current value (if there
	 * still are blocks) or increment it by one (the new block is still the
	 * one with minimum free chunks).
	 *
	 * The one exception is when the block will get completely free - in that
	 * case we will free it, se we can't use it for minFreeChunks. It however
	 * means there are no more blocks with free chunks.
	 */
	if (slab->minFreeChunks == (block->nfree - 1))
	{
		/* Have we removed the last chunk from the freelist? */
		if (dlist_is_empty(&slab->freelist[slab->minFreeChunks]))
		{
			/* but if we made the block entirely free, we'll free it */
			if (block->nfree == slab->chunksPerBlock)
				slab->minFreeChunks = 0;
			else
				slab->minFreeChunks++;
		}
	}

	/* If the block is now completely empty, free it. */
	if (block->nfree == slab->chunksPerBlock)
	{
		free(block);
		slab->nblocks--;
		context->mem_allocated -= slab->blockSize;
	}
	else
		dlist_push_head(&slab->freelist[block->nfree], &block->node);

	Assert(slab->nblocks >= 0);
	Assert(slab->nblocks * slab->blockSize == context->mem_allocated);
}
/*
 * SlabFree
 *		Frees allocated memory; memory is removed from the slab.
 */
SlabFree
Frees allocated memory; memory is removed from the slab.
SlabFree Frees allocated memory ; memory is removed from the slab .
static void
SlabFree(MemoryContext context, void *pointer)
{
	int			idx;
	SlabContext *slab = castNode(SlabContext, context);
	SlabChunk  *chunk = SlabPointerGetChunk(pointer);
	SlabBlock  *block = chunk->block;
#ifdef MEMORY_CONTEXT_CHECKING
	if (slab->chunkSize < (slab->fullChunkSize - sizeof(SlabChunk)))
		if (!sentinel_ok(pointer, slab->chunkSize))
			elog(WARNING, "detected write past chunk end in %s %p",
				 slab->header.name, chunk);
#endif
	idx = SlabChunkIndex(slab, block, chunk);
	*(int32 *) pointer = block->firstFreeChunk;
	block->firstFreeChunk = idx;
	block->nfree++;
	Assert(block->nfree > 0);
	Assert(block->nfree <= slab->chunksPerBlock);
#ifdef CLOBBER_FREED_MEMORY
	wipe_mem((char *) pointer + sizeof(int32),
			 slab->chunkSize - sizeof(int32));
#endif
	dlist_delete(&block->node);
	if (slab->minFreeChunks == (block->nfree - 1))
	{
		if (dlist_is_empty(&slab->freelist[slab->minFreeChunks]))
		{
			if (block->nfree == slab->chunksPerBlock)
				slab->minFreeChunks = 0;
			else
				slab->minFreeChunks++;
		}
	}
	if (block->nfree == slab->chunksPerBlock)
	{
		free(block);
		slab->nblocks--;
		context->mem_allocated -= slab->blockSize;
	}
	else
		dlist_push_head(&slab->freelist[block->nfree], &block->node);
	Assert(slab->nblocks >= 0);
	Assert(slab->nblocks * slab->blockSize == context->mem_allocated);
}
static void SlabFree ( MemoryContext context , void * pointer ) { int idx ; SlabContext * slab = castNode ( SlabContext , context ) ; SlabChunk * chunk = SlabPointerGetChunk ( pointer ) ; SlabBlock * block = chunk -> block ; #ifdef MEMORY_CONTEXT_CHECKING if ( slab -> chunkSize < ( slab -> fullChunkSize - sizeof ( SlabChunk ) ) ) if ( ! sentinel_ok ( pointer , slab -> chunkSize ) ) elog ( WARNING , " " , slab -> header . name , chunk ) ; #endif idx = SlabChunkIndex ( slab , block , chunk ) ; * ( int32 * ) pointer = block -> firstFreeChunk ; block -> firstFreeChunk = idx ; block -> nfree ++ ; Assert ( block -> nfree > 0 ) ; Assert ( block -> nfree <= slab -> chunksPerBlock ) ; #ifdef CLOBBER_FREED_MEMORY wipe_mem ( ( char * ) pointer + sizeof ( int32 ) , slab -> chunkSize - sizeof ( int32 ) ) ; #endif dlist_delete ( & block -> node ) ; if ( slab -> minFreeChunks == ( block -> nfree - 1 ) ) { if ( dlist_is_empty ( & slab -> freelist [ slab -> minFreeChunks ] ) ) { if ( block -> nfree == slab -> chunksPerBlock ) slab -> minFreeChunks = 0 ; else slab -> minFreeChunks ++ ; } } if ( block -> nfree == slab -> chunksPerBlock ) { free ( block ) ; slab -> nblocks -- ; context -> mem_allocated -= slab -> blockSize ; } else dlist_push_head ( & slab -> freelist [ block -> nfree ] , & block -> node ) ; Assert ( slab -> nblocks >= 0 ) ; Assert ( slab -> nblocks * slab -> blockSize == context -> mem_allocated ) ; }
SlabFree
              Frees allocated memory; memory is removed from the slab.
SlabFree Frees allocated memory ; memory is removed from the slab .
/* Test for someone scribbling on unused space in chunk */ /* compute index of the chunk with respect to block start */ /* add chunk to freelist, and update block nfree count */ /* XXX don't wipe the int32 index, used for block-level freelist */ /* remove the block from a freelist */ /*
	 * See if we need to update the minFreeChunks field for the slab - we only
	 * need to do that if there the block had that number of free chunks
	 * before we freed one. In that case, we check if there still are blocks
	 * in the original freelist and we either keep the current value (if there
	 * still are blocks) or increment it by one (the new block is still the
	 * one with minimum free chunks).
	 *
	 * The one exception is when the block will get completely free - in that
	 * case we will free it, se we can't use it for minFreeChunks. It however
	 * means there are no more blocks with free chunks.
	 */ /* Have we removed the last chunk from the freelist? */ /* but if we made the block entirely free, we'll free it */ /* If the block is now completely empty, free it. */