创建SlabContext
分配对象
创建对象池
- 分配空间
- 初始化分配的空间
- 将block加入循环双向链表
从对象池中获取对象
从双向循环链表中获取一个block
/* grab the block from the freelist (even the new block is there) */
block = dlist_head_element(SlabBlock, node,
&slab->freelist[slab->minFreeChunks]);
从block中获取空闲chunk的索引
/* we know index of the first free chunk in the block */
idx = block->firstFreeChunk;
获取chunk
/* compute the chunk location block start (after the block header) */
chunk = SlabBlockGetChunk(slab, block, idx);
减少空用chunk个数
/*
* Update the block nfree count, and also the minFreeChunks as we've
* decreased nfree for a block with the minimum number of free chunks
* (because that's how we chose the block).
*/
block->nfree--;
slab->minFreeChunks = block->nfree;
更新下一个空闲chunk索引
block->firstFreeChunk = *(int32 *) SlabChunkGetPointer(chunk);
将block重新更新到下一个循环双向链表中
/* move the whole block to the right place in the freelist */
dlist_delete(&block->node);
dlist_push_head(&slab->freelist[block->nfree], &block->node);
当block中的chunk分配完后,整个block就移动到了freelist[0]的位置,freelist[0]下的循环双向链表的节点都是分配完的block
释放对象
根据释放对象,获取到对应的block以及chunk
SlabChunk *chunk = SlabPointerGetChunk(pointer);
SlabBlock *block = chunk->block;
计算当前chunk相对于block的索引
/* compute index of the chunk with respect to block start */
idx = SlabChunkIndex(slab, block, chunk);
更新空闲chunk索引以及空闲chunk个数
/* add chunk to freelist, and update block nfree count */
*(int32 *) pointer = block->firstFreeChunk;
block->firstFreeChunk = idx;
block->nfree++;
将当前block从现有循环双向链表中删除
/* remove the block from a freelist */
dlist_delete(&block->node);
如果释放的chunk所属的block是正用于申请空间的freelist,并且freelist也空了,则更新minFreeChunks
/*
* 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++;
}
}
释放block或这加入另外一个循环双向链表中
/* 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);