上一篇:iOS标准库中常用数据结构和算法之位串

⛲️内存池

内存池提供了内存的复用和持久的存储功能。设想一个场景,当你分配了一块大内存并且填写了内容,但是你又不是经常去访问这块内存。这样的内存利用率将不高,而且无法复用。而如果是采用内存池则可以很轻松解决这个问题:你只需要从内存池中申请这块内存,设置完内容后当不需要用时你可以将这块内存放入内存池中,供其他地方在申请时进行复用,而当你再次需要时则只需要重新申请即可。内存池提供了内存分配编号而且设置脏标志的概念,当你把分配的内存放入内存池并设置脏标志后,系统就会在适当的时候将这块内存的内容写回到磁盘,这样当你再次根据内存编号来访问内存时,系统就又会从磁盘中将内容读取到内存中去。

功能:在iOS中提供了一套内存池管理的API,你可以用这套API来实现上述的功能,而且系统内部很多功能也是借助内存池来实现内存复用和磁盘存储的。

头文件: #include <mpool.h>

平台: BSD系统,linux系统

一、内存池的创建、同步和关闭

功能:创建和关闭一个内存池对象并和磁盘文件绑定以便进行同步操作。

函数签名


//创建一个内存池对象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.

描述

  1. 内存池中的内存的分配和获取是以页为单位进行的,每次分配的页的尺寸大小由pagesize指定,同时内存池也指定了最大的缓存页数量maxcache。每次从内存池中分配一页内存时,除了会返回分配的内存地址外,还会返回这一页内存的编号。这个编号对于内存池中的内存页来说是唯一的。因为内存池中的内存是可以被复用的,因此就有可能是不同的编号的内存页所得到的内存地址是相同的。

  2. 每一个内存池对象都会要和一个文件关联起来,以便能够实现内存数据的永久存储和内存的复用。文件句柄必须用open函数来打开,比如下面的例子:

 int fd = open("/Users/apple/mpool", O_RDWR|O_APPEND|O_CREAT,0660);
复制代码
  1. 当我们不需要使用某个内存页时或者内存页的内容有改动则我们需要将这个内存页放入回内存池中,并将页标志为脏标志。这样系统就会在适当的时候将此内存页的数据写回到磁盘文件中,同时此内存页也会在后续被重复利用。

  2. 当我们想将所有设置为脏标志的内存页立即写入磁盘时则需要调用mpool_sync函数进行同步处理。

  3. 当我们不再需要内存池时,则可以通过mpool_close来关闭内存池对象,需要注意的是关闭内存池并不会将内存中的数据回写到磁盘中去。

二、内存池中内存的获取

功能: 从内存池中申请分配一页新的内存或者获取已有缓存中的内存。

函数签名:

//从内存池中申请分配一页新的内存
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。

描述:

  1. 无论是new还是get每次从内存池里面分配或者获取的内存页的大小都是由上述mpool_open函数中的pagesize参数指定的大小。
  2. 系统内部分配的内存是用calloc函数实现的,但是我们不需要手动调用free来对内存进行释放处理。
  3. 每个内存页都有一个唯一的页编号,而且每次分配的页编号也会一直递增下去。
  4. mpool_new函数申请分配新的内存时,如果当前缓存中的内存页小于maxcache数量则总是分配新的内存,只有当缓存数量大于maxcache时才会从现有的缓存中寻找一页可以被重复利用的内存页,如果没有可以重复利用的页面,则会继续分配新的内存页。
  5. mpool_get函数则根据内存页的编号获取对应的内存页。如果编号不存在则返回NULL。需要注意的是一般在获取了某一页内存后,不要进行重复获取操作,否则在DEBUG状态下会返回异常。另外一个情况是有可能相同的页编号下两次获取的内存地址是不一样的,因为系统实现内部有内存复用的机制。

三、内存池中内存的放回

功能:将分配或者申请的内存页放回到内存池中去,以便进行重复利用。

函数签名:

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

描述

  1. 这个函数用来将内存页放入回内存池缓存中,以便对内存进行重复利用。当将某个内存地址放入回缓存后,将不能再次访问这个内存地址了。如果要想继续访问内存中的数据则需要借助上述的mpool_get/new函数来重新获取。
  2. flags:属性如果指定为0时,表明放弃这次内存中的内容的修改,系统不会将内存中的内容写入到磁盘中,而只是将内存放入缓存中供其他地方重复使用。而如果设置为MPOOL_DIRTY时,则表明将这页内存中的数据设置为脏标志,除了同样将内存放入缓存中重复利用外,则会在适当的时候将内存中的数据写入到磁盘中,以便下次进行读取。

四、内存池磁盘读写通知

功能:注册回调函数,当某页内存要写回到磁盘或者要从磁盘中读取时就会调用指定的回调函数。

函数签名:

void mpool_filter(MPOOL *mp, void (*pgin)(void *, pgno_t, void *),void (*pgout)(void *, pgno_t, void *), void *pgcookie);
复制代码

参数:

mp:[in] 内存池对象.

pgin: [in]: 回调函数,当某个内存页的数据需要从磁盘读取时,会在读取完成后调用这个回调函数。

pgout:[in]: 回调函数,当某个内存页的数据要到磁盘时,会在写入完成后调用这个回调函数。

pgcookie: [in] 上述两个回调函数的附加参数。

描述

因为内存池中的内存页会进行复用,以及会在适当的时候将内容同步到磁盘中,或者从磁盘中将内容读取到内存中,因此可以借助这个函数来监控这些磁盘文件和内存之间的读写操作。pgin和pgout函数的格式定义如下:

//pgin和pgout回调函数的格式。
//pgcookie:是mpool_filter函数中传入的参数。
//pgno: 要进行读写的内存页编号
//pageaddr: 要进行读写的内存地址。
void (*pgcallback)(void *pgcookie, pgno_t pgno, void *pageaddr);复制代码

五、示例代码

 //创建并打开一个文件。int fd = open("/Users/apple/mpool", O_RDWR|O_APPEND|O_CREAT,0660);//创建一个内存池对象,每页的内存100个字节,最大的缓存数量为4MPOOL *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系统底层开发提供了一个非常重要的能力,我们可以好好利用内存池来对内存进行管理,以及一些需要进行持久化的数据也可以借助内存池来进行保存,通过内存池提高内存的重复利用率。

iOS标准库中常用数据结构和算法之内存池相关推荐

  1. keilcjson内存分配失败_iOS标准库中常用数据结构和算法之内存池

    黑客技术点击右侧关注,了解黑客的世界! Java开发进阶点击右侧关注,掌握进阶之路! Linux编程点击右侧关注,免费入门到精通! 作者丨欧阳大哥2013https://www.jianshu.com ...

  2. iOS标准库中常用数据结构和算法之二叉排序树

    上一篇:iOS标准库中常用数据结构和算法之排序 ?二叉排序树 功能:二叉排序树的标准实现是一颗平衡二叉树.二叉排序树主要用来解决高效插入和高效检索以及进行排序的问题.系统分别提供了二叉排序树节点的查找 ...

  3. C++知识点26——使用C++标准库(常用的泛型算法1)

    C++中实现了很多的泛型算法,大约100多个,使用前要添加#include<algorithm> 下面介绍的基本可以满足绝大部分需求,其他的用到再查 一.计数算法 1.count temp ...

  4. C++知识点27——使用C++标准库(常用的泛型算法2)

    接上一篇博客https://blog.csdn.net/Master_Cui/article/details/108404257 八.删除元素 template <class ForwardIt ...

  5. ollections 库中常用的 4 个数据结构

    collections 库是标准库的一部分,里面有很多数据结构,在列表.字典.元组的基础上做了很多修改和提升. 今天就来说说最有用的几个. 1.deque 它实现了两端都可以操作的队列,相当于双端队列 ...

  6. 聊聊C++11标准库中堆(heap)算法的源码

    STL中支持堆操作,对外暴露了std::make_heap,std::push_heap,std::pop_heap,std::sort_heap,std::is_heap,std::is_heap_ ...

  7. php spl函数,PHP SPL标准库中的常用函数介绍

    这篇文章主要介绍了PHP SPL标准库中的常用函数介绍,本文着重讲解了spl_autoload_extensions().spl_autoload_register().spl_autoload()三 ...

  8. 面试常考的常用数据结构与算法

    面试常考的常用数据结构与算法 数据结构与算法,这个部分的内容其实是十分的庞大,要想都覆盖到不太容易.在校学习阶段我们可能需要对每种结构,每种算法都学习,但是找工作笔试或者面试的时候,要在很短的时间内考 ...

  9. C++标准库中的随机数生成

    C++标准库中的随机数生成 一.伪随机与真随机 数字计算机的结果可以说是固定的.必然的.都是根据现有数据的状态得出接下来的状态.除非硬件损坏,计算机不会产生真正的随机和无法预料的事.在生活中随手抛一个 ...

最新文章

  1. swift实现ios类似微信输入框跟随键盘弹出的效果
  2. 1675: [Usaco2005 Feb]Rigging the Bovine Election 竞选划区(题解第二弹)
  3. Linux中的configure、pkg-config、pkg_config_path和安装中的PKG_CONFIG_PATH问题 pkgconfig
  4. linux中sqlplus不能用_装修中不能用海沙,但是海沙已经偷偷走进了你的家
  5. 在同一session内创建, 修改和删除IBASE component
  6. 深度学习之生成对抗网络(2)GAN原理
  7. 微软AirSim,一个无人机和机器人的模拟器
  8. P2601 [ZJOI2009]对称的正方形(二维哈希)(二分)
  9. 分布式事务实践--Spring的全局事务JTA
  10. Python3——列表:Python主力
  11. Python编程 从入门到实践 第2版
  12. caffe教程笔记《Blobs, Layers, and Nets》
  13. 苹果企业开发者账号申请攻略
  14. python对气象工作有没有用_Python语言在气象资料下载中的应用
  15. c语言去除字符串中字母,C语言经典例题100例——C语言练习实例32解答(在字符串中删除指定字母或字符串)...
  16. Java 9 模块化(Modularity)
  17. ios 结构体跟枚举变量的区别_[Swift]枚举、类与结构体的对比
  18. 斐波那契数列类 python实现
  19. beamforming与天线阵列的间距天线数的关系仿真
  20. 专家推荐 基础JS特效代码

热门文章

  1. Android中获取系统内存信息以及进程信息-----ActivityManager的使用(一)
  2. Nginx 进阶 (ssl、fpm、rewrite、cache配置等)
  3. 打印二叉树和为某一值的路径
  4. MySQL中varchar类型在5.0.3后的变化
  5. 文本占用的高度和范围
  6. 【Win 10 应用开发】将墨迹保存到图像的两种方法
  7. trigger() --工作中问题nav样式
  8. 关于SurfaceView相机预览获取Bitmap的方法
  9. 服务器安全配置之注册表设置
  10. plsql查找不到带中文的纪录