内存池提供了内存的复用和持久的存储功能。设想一个场景,当你分配了一块大内存并且填写了内容,但是你又不是经常去访问这块内存。这样的内存利用率将不高,而且无法复用。而如果是采用内存池则可以很轻松解决这个问题:你只需要从内存池中申请这块内存,设置完内容后当不需要用时你可以将这块内存放入内存池中,供其他地方在申请时进行复用,而当你再次需要时则只需要重新申请即可。内存池提供了内存分配编号而且设置脏标志的概念,当你把分配的内存放入内存池并设置脏标志后,系统就会在适当的时候将这块内存的内容写回到磁盘,这样当你再次根据内存编号来访问内存时,系统就又会从磁盘中将内容读取到内存中去。
功能:在iOS中提供了一套内存池管理的API,你可以用这套API来实现上述的功能,而且系统内部很多功能也是借助内存池来实现内存复用和磁盘存储的。 头文件: #include <mpool.h> 平台: iOS系统,BSD系统。
功能:创建和关闭一个内存池对象并和磁盘文件绑定以便进行同步操作。 函数签名:
//创建一个内存池对象
MPOOL * mpool_open(void *key, int fd, pgno_t pagesize, pgno_t maxcache);
//将内存池中的脏数据同步写回到磁盘文件中
int mpool_sync(MPOOL *mp);
//关闭和销毁内存池对象。
int mpool_close(MPOOL *mp);
参数: key:[in] 保留字段,暂时没有用处,传递NULL即可。 fd:[in] 内存池关联的磁盘文件句柄,文件句柄需要用open函数来打开。 pagesize:[in] 内存池中每次申请和分配的内存的尺寸大小,单位是字节。 maxcache:[in] 内存池中内存页的最大缓存数量。如果池中缓存的内存数量超过了最大缓存的数量就会复用已经存在的内存,而不是每次都分配新的内存。 return:[out] 返回一个新创建的内存池对象,其他两个函数成功返回0,失败返回非0.
描述:
int fd = open("/Users/apple/mpool", O_RDWR|O_APPEND|O_CREAT,0660);
功能: 从内存池中申请分配一页新的内存或者获取现有缓存中的内存。 函数签名:
//从内存池中申请分配一页新的内存
void * mpool_new(MPOOL *mp, pgno_t *pgnoaddr);
//根据内存编号页获取对应的内存。
void * mpool_get(MPOOL *mp, pgno_t pgno, u_int flags);
参数: mp:[in] 内存池对象。 pgnoaddr:[out] 用于mpool_new函数,用于保存新分配的内存页编号。 pngno:[in] 用于mpool_get函数,指定要获取的内存页的编号。 flags:[in] 此参数暂时无用。 return:[out] 返回分配或者获取的内存地址。如果分配或者获取失败则返回NULL。 描述:
功能:将分配或者申请的内存页放回到内存池中去,以便进行重复利用。 函数签名:
int mpool_put(MPOOL *mp, void *pgaddr, u_int flags);
参数: mp: [in] 内存池对象。 pgaddr:[in] 要放入缓存的内存页地址。这个地址由mpool_get/new两个函数返回。 flags:[in] 放回的属性,一般设置为0或者MPOOL_DIRTY。 return:[in] 函数调用成功返回0,失败返回非0
描述:
//创建并打开一个文件。
int fd = open("/Users/apple/mpool", O_RDWR|O_APPEND|O_CREAT,0660);
//创建一个内存池对象,每页的内存100个字节,最大的缓存数量为4
MPOOL *pool = mpool_open(NULL, fd, 100, 4);
//从内存池中分配一个新的内存页,这里对返回的内存填写数据。
pgno_t pidx1, pidx2 = 0;
char *mem1 = (char*)mpool_new(pool, &pidx1);
memcpy(mem1, "aaa", 4);
char *mem2 = (char*)mpool_new(pool, &pidx2);
memcpy(mem2, "bbb", 4);
//将分配的内存mem1放回内存池中,但是内容不保存到磁盘
mpool_put(pool, mem1, 0);
//将分配的内存mem2放回内存池中,但是内容保存到磁盘。
mpool_put(pool, mem2, MPOOL_DIRTY);
//经过上面的操作后mem1,mem2将不能继续再访问了,需要访问时需要再次调用mpool_get。
mem1 = (char*)mpool_get(pool, pidx1, 0);
mem2 = (char*)mpool_get(pool, pidx2, 0);
//上面的mem1和mem2可能和前面的new返回的地址是不一样的。因此在内存池中不能通过地址来做唯一比较,而应该将编号来进行比较。
//将所有设置为脏标志的内存也写回到磁盘中去。
mpool_sync(pool);
mpool_close(pool); //关闭内存池。
close(fd); //关闭文件。
内存池为iOS系统底层开发提供了一个非常重要的能力,我们可以好好利用内存池来对内存进行管理,以及一些需要进行持久化的数据也可以借助内存池来进行保存,通过内存池提高内存的重复利用率。