内存池
来源:互联网 发布:mysql 删除表怎么恢复 编辑:程序博客网 时间:2024/05/19 14:01
链表是大家非常熟悉的数据结构,使用频率也非常高,但是链表有几个缺点。首先,我们每创建一个节点,都要进行一下系统调用分配一块空间,这会浪费一点时间;其次,由于创建节点的时间不固定,会导致节点分配的空间不连续,容易形成离散的内存碎片;最后,由于内存不连续,所以链表的局部访问性较差,容易出现cache缺失。
针对链表的上述问题,在实际工作中,我们很少直接用链表,而是采用链表的替代品—内存池。上过操作系统课程的同学对内存池应该不陌生,而且应该也知道设计一个好的内存池非常麻烦。但替换链表的内存池做了很大的简化:它是单线程的而且是只支持固定块大小的内存池。在具体实现过程中,我们先分配N块固定大小的连续内存,N块需要根据需求设定,之后每需要一个节点就从内存池中get一块空闲的块,用完之后再回收到内存池中。
内存池可以解决链表三个问题中的前两个,不能解决后一个,但是如果内存池较小可以缓解cache缺失的问题,整体而言还是可以很好地代替链表。下面看一下具体实现。
1. 结构体
内存池想象中比较简单,就是首先分配一块大内存,每次取一小块内存,用完再放回去即可,但是实现起来需要较多的辅助变量。我们不能仅仅通过一个指针来完成对内存池的访问,因为获取和释放的顺序是随机的。我们需要标记每一块的使用状况。内存池的结构体如下:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
buffer_arr就是原始的整块大内存,除了这个变量之外还有三个二维指针:index_arr是一个指针数组,分别指向每一块的首地址,index_cur是一个遍历指针,用来指向当前可分配的块,index_end表示可分配块的末尾。
2. 初始化
初始化需要指定块大小和块个数,然后分配大块内存。但初始化的关键操作是初始化几个二维指针。看一下代码:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
index_arr是一个和内存池容量一样的二维指针,它被初始化为内存池每一块的首地址。index_end指向index_arr末尾的下一个位置,用来表示内存池的末尾。index_cur只是简单地等于index_arr的首地址。后面我们就可以通过加减index_cur来分配或回收一块内存。
3. get函数
get函数的目的是从内存池中取一块可用内存,它首先判断是否还有可用块,如果有就返回当前可用块。返回可用块的方法很简单,只需要将index_cur对应位置的块返回即可。
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
4. free函数
free函数的目的是回收一块用完的内存。和get相反,我们只需要把回收内存的地址赋给index_cur-1即可。
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
这里需要注意的是,index_arr一开始是顺序指向每一块内存的,但是在不停地get和free过程中index_arr开始乱序指向每一块内存。
可以看出,上面的get和free操作都非常简单,只是简单的加减操作,所以速度非常快,而且内存池是一整块内存,不存在内存碎片的问题。同时,如果内存池较小,也可以很大程度上缓解cache缺失问题。
- 内存_内存池
- 内存池
- 内存池
- 内存池
- 内存池
- 内存池
- 内存池
- 内存池
- 内存池
- 内存池
- 内存池
- 内存池
- 内存池
- 内存池
- 内存池
- 内存池
- 内存池
- 内存池
- 短信验证码接口的实现
- CefSharp语言(Locales)配置问题
- 多线程(上)
- 位操作-leetcode 461 Hamming Distance
- Promoise 的相关知识
- 内存池
- Redis安装部署与维护详解
- activiti初识25张表------HelloWorld
- 利用CGI环境变量和符号链接减小CGI程序体积
- 用Jackson取得城市json的经纬度
- PAT乙级 1006. 换个格式输出整数 (15)
- Deep Learning in NLP (一)词向量和语言模型
- vc2008/vc2015 和 Mac 编译 zlib-1.2.8
- Labview学习笔记_如何更改Numberic Control的基数显示