第一步是先调用_pool_new创建一个空的内存池结构,这个前面已经说明了,操作很简单。看第二步是怎么完成的 static struct pheap *_pool_heap(pool_t p, int size) { struct pheap *ret; struct pfree *clean; while((ret = _pool__malloc(sizeof(struct pheap))) == NULL) sleep(1); while((ret->block = _pool__malloc(size)) == NULL) sleep(1); ret->size = size; p->size += size; ret->used = 0; 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); return ret; } 第二步包含下面一些操作: 1、申请一个大小为size的内存块,也就是前方中介绍的pheap结构。 2、把这个内存块的大小size,加到内存池上,就是那个p->size += size; 3、将内存块关联到struct pfree结构。这会指示内存释放的方式,也把内存加入到链表元素上。 4、将struct pfree结构关联到内存池,其实就是加到链表的末尾。 下面会讨论第3和第4部是怎么实现的。 五、内存池管理内存机制(单链表管理结构) 这里主要是讨论,从内存块申请开始,就是申请了一个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结构【这是内存池的结构】的链表末尾。 六、内存池的释放 在内存池的使命结束后,我们需要释放内存池,不仅仅是struct pool_struct这个结构,还包括链表上的内存块。 void pool_free(pool_t p) { struct pfree *cur, *stub; if(p == NULL) return; cur = p->cleanup; while(cur != NULL) { (*cur->f)(cur->arg); // 这会释放用malloc分配的内存块和struct pheap结构所占用的内存。这就是前文的_pool_heap_free函数 stub = cur->next; free(cur); // 释放pfree结构。 cur = stub; } free(p); //释放pool_struct结构所占用的内存。 } |