什么是内存池?

在上一篇 C++内存管理:new / delete 和 cookie中谈到,频繁的调用 malloc 会影响运行效率以及产生额外的 cookie, 而内存池的思想是预先申请一大块内存,当有内存申请需求时,从内存池中取出一块内存分配给目标对象。

它的实现过程为:

  1. 预先申请 chunk 大小的内存池, 将内存池划按照对象大小划分成多个内存块。
  2. 以链表的形式,即通过指针将内存块相连,头指针指向第一个空闲块。
  3. 当有内存申请需求时,首先检查头指针是否指向空闲块,如果是则将头指针指向的第一个空闲块分配出去(从链表移除),同时头指针指向下一个空闲块;若头指针为空,说明当前内存池已分配完,需要重新申请新的内存池。
  4. 当有内存释放需求时,将释放的内存块重新加入链表的表头,调整头指针指向新加入的空闲块。这也意味着,如果申请了多个内存池,在内存释放的过程中会慢慢的合并到一起。

初步实现

#include <iostream>
using namespace std; class Screen {
public:
Screen(int x) : i(x) { };
int get() { return i; } void* operator new(size_t);
void operator delete(void*, size_t); private:
Screen* next;
static Screen* freeStore; //头指针
static const int screenChunk; //内存块数量
private:
int i;
}; Screen* Screen::freeStore = 0;
const int Screen::screenChunk = 5; void* Screen::operator new(size_t size){
Screen *p;
if (!freeStore) { //内存池是空的
size_t chunk = screenChunk * size;
freeStore = p = reinterpret_cast<Screen*>(new char[chunk]);
for (; p != &freeStore[screenChunk - 1]; ++p) { //以链表的形式串联起来
p->next = p + 1;
}
p->next = 0;
}
p = freeStore;
freeStore = freeStore->next;
return p;
} void Screen::operator delete(void *p, size_t){
//将内存块重新加入链表表头,同时调整头指针
(static_cast<Screen*>(p))->next = freeStore;
freeStore = static_cast<Screen*>(p);
} //-------------
void test(){ cout << "Size: " << sizeof(Screen) << endl; size_t const N = 100;
Screen* p[N]; for (int i = 0; i < N; ++i)
p[i] = new Screen(i); for (int i = 0; i < 10; ++i) //输出地址观察
cout << i << ": " << p[i] << endl; for (int i = 0; i < N; ++i)
delete p[i];
} int main(){
test();
return 0;
}

在上面的代码中设置一个内存池为5个内存块,当我们进行100次内存申请后,打印出前10个地址查看,可以看到前5个地址是连续的,后5个也是连续的,但中间由于重新申请了内存池,所以不是连续的。

但是这样的方法还存在着问题,那就是引入了额外的指针内存消耗,接下来将使用embeded pointer进行改进。

使用嵌入指针改进

上面就使用到了嵌入指针,一个 AirplaneRep 对象的大小为 8 字节,而一个 Airplane 的指针大小为 4 字节或 8 字节。在 32 位机器下, 指针可以借用 AirplaneRep 对象所占的 8 字节内存空间中的前 4 个字节,用来连接空闲的内存块。而当内存块需要被分配给对象时,此时它已从链表中移除,也就不需要指针来连接了。此时的 8 字节内存空间由 AirplaneRep 占据。当内存释放时也是同理,由于 Rep 和 next 不会同时用到,所以 embeded pointer 的做法可以减少内存消耗。

 参考:

  1. 【C++内存管理】内存管理实例 (二) —— Embeded pointer

  2. 嵌入式指针embedded pointer的概念以及用法

最新文章

  1. 让Visual Studio Code对jQuery支持智能提示!
  2. 分享一些不错的sql语句
  3. php ajax请求和返回
  4. GitHub注册账号
  5. https封装类,支持get/post请求
  6. 洛谷P2723 丑数 Humble Numbers
  7. SQL IDENTITY(int,1,1) 用法
  8. JS实现登录页面记住密码和enter键登录
  9. double类型字符串转换成一个纯数字字符串和一个小数点位数的c++代码
  10. [C++] 对象地址与接口指针的故事
  11. 认识IL代码---从开始到现在 &lt;第二篇&gt;
  12. 灰色关联度Matlab代码
  13. CXF_Spring_Rest
  14. Intellij导入子项目时,maven列表子项目灰色不可用---解决方法
  15. 详谈Javascript类与继承
  16. 【自制工具类】struts返回json数据包装格式类
  17. C语言链表的建立、插入和删除
  18. A.01.03-模块的输入—模拟量输入
  19. JSON转Excel
  20. 《算法》第三章部分程序 part 6

热门文章

  1. 快速搭建 kvm web 管理工具 WebVirtMgr
  2. Prometheus+Grafana监控Kubernetes
  3. Linux驱动实践:你知道【字符设备驱动程序】的两种写法吗?
  4. 04373 C++程序设计 2019版 第一章习题五、程序设计题
  5. Hi3516开发笔记(三):Hi3516虚拟机基础环境搭建之交叉编译环境境搭建以及开机启动脚本分析
  6. 最强最全面的Hive SQL开发指南,超四万字全面解析
  7. Geotools核心特点以及支持数据的格式和标准
  8. [NOI2021] 量子通信
  9. 【豆科基因组】普通豆/菜豆/四季豆Common bean (Phaseolus vulgaris L.) 基因组
  10. 23-Longest Substring Without Repeating Characters