五、内存池管理内存机制(单链表管理结构)

  这里主要是讨论,从内存块申请开始,是申请了一个pheap结构指向内存块,然后内存池以什么形式将内存块组织起来,这一个很重要的结构是struct pfree结构。

  看一下前面申请内存块之后,这时还只是一个pheap结构,没有和内存池关联起来,在前方我们看到,是通过下面代码进行关联的

    clean = _pool_free(p, _pool_heap_free, (void *)ret);
    clean->heap = ret; /* for future use in finding used mem for pstrdup */
    _pool_cleanup_append(p, clean);

  _pool_free为该内存块定义的一个结构进行初始化,如下调用

static struct pfree *_pool_free(pool_t p, pool_cleanup_t f, void *arg)
{
    struct pfree *ret;
    while((ret = malloc(sizeof(struct pfree))) == NULL) sleep(1);
    ret->f = f;
    ret->arg = arg;
    ret->next = NULL;

    return ret;
}

  这个函数只是定义了一个sturct pfree结构,基本上是用struct pheap这个结构对其进行初始化的,可以看出这个结构的arg和heap域都是指向struct pheap结构。这是很重要的一步,内存池主要是管理这个结构的。

  注意这里的pool_cleanup_t是一个函数指针,在我们这里,它是_pool_heap_free。用于指示如何释放这个内存块,实现很简单,如下:

static void _pool_heap_free(void *arg)
{
    struct pheap *h = (struct pheap *)arg;
    free(h->block);
    free(h);
}

  这个释放函数很简单了吧,下面继续我们话题。

  前文说了内存池包含链表,管理内存块,那接下来的操作是不是要将这个内存块【struct pfree】加到链表上。看一下_pool_cleanup_append函数做哪些工作:

static void _pool_cleanup_append(pool_t p, struct pfree *pf)
{
    struct pfree *cur;

    if(p->cleanup == NULL)
    {
        p->cleanup = pf;
        p->cleanup_tail = pf;
        return;
    }

    cur = p->cleanup_tail;
    cur->next = pf;
    p->cleanup_tail = pf;
}

  这个函数很简单,将struct pfree结构加到内存池的cleanup_tail链表的末尾,并将新的cleanup_tail指向刚加入的pfree结构。

  到这里,完成了内存从调用malloc分配至加入到内存池的过程,再回顾一下:

  1、调用malloc分配内存块,并赋值给struct pheap结构。

  2、将struct pheap结构封装成struct pfree结构,这样struct pheap结构可以成为链表上的元素。

  3、将struct pfree结构加入到struct pool_sturct结构【这是内存池的结构】的链表末尾。