- 浏览: 369858 次
- 性别:
- 来自: 苏州
文章分类
- 全部博客 (335)
- C++ (190)
- 设计模式 (43)
- 数据库技术 (5)
- 网络编程 (11)
- 自动化测试 (6)
- Linux (13)
- OpenSSL (10)
- MS Crypt API (5)
- SCM (2)
- English (4)
- Android (10)
- EMV规范 (1)
- Saturn Platform (0)
- C (10)
- SQL (2)
- ASP.NET (3)
- 英语口语学习 (3)
- 调试工具 (21)
- 编译技术 (5)
- UML (1)
- 项目管理 (5)
- 敏捷开发 (2)
- Http Server (6)
- 代码审查、代码分析 (5)
- 面试基础 (10)
- 重点知识 (16)
- STL (6)
- Efficient C++资料 (8)
- 数据结构和算法 (7)
- 读书笔记 (0)
- 开源项目 (4)
- 多线程 (2)
- Console App (6)
- 个人开源项目 (4)
- IBM DevelopWorks (4)
- Java (16)
- 内存泄漏相关调试和检测 (13)
- 软件测试相关技术 (2)
- C# (11)
- Apple Related (1)
- 软件测试和管理 (2)
- EMV (1)
- Python (1)
- Node.js (6)
- JavaScript (5)
- VUE (1)
- Frontend (1)
- Backend (4)
- RESTful API (3)
- Firebase (3)
最新评论
-
u013189503:
来个密码吧
[C++][Logging] 项目中写日志模块的实现 -
wyf_vc:
来个密码啊!!
[C++][Logging] 项目中写日志模块的实现
转自
http://cplusplus.wikidot.com/cn:dive-into-memory-pool
内存池(MemPool)技术备受推崇。我用google搜索了下,没有找到比较详细的原理性的文章,故此补充一个。另外,补充了boost::pool组件与经典MemPool的差异。同时也描述了MemPool在sgi-stl/stlport中的运用。
经典的内存池(MemPool)技术,是一种用于分配大量大小相同的小对象的技术。通过该技术可以极大加快内存分配/释放过程。下面我们详细解释其中的奥妙。
经典的内存池只涉及两个常量:MemBlockSize、ItemSize(小对象的大小,但不能小于指针的大小,在32位平台也就是不能小于4字节),以及两个指针变量MemBlockHeader、FreeNodeHeader。开始,这两个指针均为空。
其中指针变量MemBlockHeader是把所有申请的内存块(MemBlock)串成一个链表,以便通过它可以释放所有申请的内存。FreeNodeHeader变量则是把所有自由内存结点(FreeNode)串成一个链。
这段话涉及两个关键概念:内存块(MemBlock)和自由内存结点(FreeNode)。内存块大小一般固定为MemBlockSize字节(除去用以建立链表的指针外)。内存块在申请之初就被划分为多个内存结点(Node)1,每个Node大小为ItemSize(小对象的大小),计MemBlockSize/ItemSize个。这MemBlockSize/ItemSize个内存结点刚开始全部是自由的,他们被串成链表。我们看看申请/释放内存过程,就很容易明白这样做的目的。
代码如下:
内存申请过程分为两种情况:
在自由内存结点链表(FreeNodeList)非空。在此情况下,Alloc过程只是从链表中摘下一个结点的过程。
否则,意味着需要一个新的内存块(MemBlock)。这个过程需要将新申请的MemBlock切割成多个Node,并把它们串起来,MemPool技术的开销主要在这。
代码如下:
释放过程极其简单,只是把要释放的结点挂到自由内存链表(FreeNodeList)的开头即可。
MemPool技术申请内存/释放内存均极其快(比AutoFreeAlloc慢)。其内存分配过程多数情况下复杂度为O(1),主要开销在FreeNodeList为空需要生成新的MemBlock时。内存释放过程复杂度为O(1)。
boost::pool
boost::pool是内存池技术的变种。主要的变化如下:
MemBlock改为非固定长度(MemBlockSize),而是:第1次申请时m_nItemSize*32,第2次申请时 m_nItemSize*64,第3次申请时m_nItemSize*128,以此类推。不采用固定的MemBlockSize,而采用这种做法预测模型2,是一个细节上的改良。
增加了ordered_free(void* p) 函数。ordered_free区别于free的是,free把要释放的结点挂到自由内存链表(FreeNodeList)的开头, ordered_free则假设FreeNodeList是有序的,因此会遍历FreeNodeList把要释放的结点插入到合适的位置。我们已经看到,free的复杂度是O(1),非常快。但请注意ordered_free是比较费的操作,其复杂度是O(N)。这里N是FreeNodeList的大小。对于一个频繁释放/申请的系统,这个N很可能是个大数。这个boost描述得很清楚:http://www.boost.org/libs/pool/doc/interfaces/pool.html
注意:不要认为boost提供ordered_free是多此一举。后文我们会在讨论boost::object_pool时解释这一点。
SGI STL把内存池(MemPool)技术进行发扬光大,用它来实现其最根本的allocator。
其大体的思想是,建立16个MemPool,<=8字节的内存申请由0号MemPool分配,<=16字节的内存申请由1号 MemPool分配,<=24字节的内存有2号MemPool分配,以此类推。最后,>128字节的内存申请由普通的malloc分配。
遗憾的是,MemPool技术可能导致内存占用只增不减。还没有非常有效的办法去避免这种情况的发生。不过我后来在ScopeAlloc的实现中发现BlockPool(是一个简化版的内存池)反倒避免了这一缺陷。
以上代码属于伪代码(struct _FreeNode、_MemBlock编译通不过),并且去除了出错处理。
Footnotes
1. boost:pool/object_pool 中称之为块(Chunk)。
2. 是的,这是一种用户内存需求的预测模型,其实std::vector的内存增长亦采用了该模型。
http://cplusplus.wikidot.com/cn:dive-into-memory-pool
概述
内存池(MemPool)技术备受推崇。我用google搜索了下,没有找到比较详细的原理性的文章,故此补充一个。另外,补充了boost::pool组件与经典MemPool的差异。同时也描述了MemPool在sgi-stl/stlport中的运用。
经典的内存池技术
经典的内存池(MemPool)技术,是一种用于分配大量大小相同的小对象的技术。通过该技术可以极大加快内存分配/释放过程。下面我们详细解释其中的奥妙。
经典的内存池只涉及两个常量:MemBlockSize、ItemSize(小对象的大小,但不能小于指针的大小,在32位平台也就是不能小于4字节),以及两个指针变量MemBlockHeader、FreeNodeHeader。开始,这两个指针均为空。
class MemPool { private: const int m_nMemBlockSize; const int m_nItemSize; struct _FreeNode { _FreeNode* pPrev; BYTE data[m_nItemSize - sizeof(_FreeNode*)]; }; struct _MemBlock { _MemBlock* pPrev; _FreeNode data[m_nMemBlockSize/m_nItemSize]; }; _MemBlock* m_pMemBlockHeader; _FreeNode* m_pFreeNodeHeader; public: MemPool(int nItemSize, int nMemBlockSize = 2048) : m_nItemSize(nItemSize), m_nMemBlockSize(nMemBlockSize), m_pMemBlockHeader(NULL), m_pFreeNodeHeader(NULL) { } };
其中指针变量MemBlockHeader是把所有申请的内存块(MemBlock)串成一个链表,以便通过它可以释放所有申请的内存。FreeNodeHeader变量则是把所有自由内存结点(FreeNode)串成一个链。
这段话涉及两个关键概念:内存块(MemBlock)和自由内存结点(FreeNode)。内存块大小一般固定为MemBlockSize字节(除去用以建立链表的指针外)。内存块在申请之初就被划分为多个内存结点(Node)1,每个Node大小为ItemSize(小对象的大小),计MemBlockSize/ItemSize个。这MemBlockSize/ItemSize个内存结点刚开始全部是自由的,他们被串成链表。我们看看申请/释放内存过程,就很容易明白这样做的目的。
申请内存过程
代码如下:
void* MemPool::malloc() // 没有参数 { if (m_pFreeNodeHeader == NULL) { const int nCount = m_nMemBlockSize/m_nItemSize; _MemBlock* pNewBlock = new _MemBlock; pNewBlock->data[0].pPrev = NULL; for (int i = 1; i < nCount; ++i) pNewBlock->data[i].pPrev = &pNewBlock->data[i-1]; m_pFreeNodeHeader = &pNewBlock->data[nCount-1]; pNewBlock->pPrev = m_pMemBlock; m_pMemBlock = pNewBlock; } void* pFreeNode = m_pFreeNodeHeader; m_pFreeNodeHeader = m_pFreeNodeHeader->pPrev; return pFreeNode; }
内存申请过程分为两种情况:
在自由内存结点链表(FreeNodeList)非空。在此情况下,Alloc过程只是从链表中摘下一个结点的过程。
否则,意味着需要一个新的内存块(MemBlock)。这个过程需要将新申请的MemBlock切割成多个Node,并把它们串起来,MemPool技术的开销主要在这。
释放内存过程
代码如下:
void MemPool::free(void* p) { _FreeNode* pNode = (_FreeNode*)p; pNode->pPrev = m_pFreeNodeHeader; m_pFreeNodeHeader = pNode; }
释放过程极其简单,只是把要释放的结点挂到自由内存链表(FreeNodeList)的开头即可。
性能分析
MemPool技术申请内存/释放内存均极其快(比AutoFreeAlloc慢)。其内存分配过程多数情况下复杂度为O(1),主要开销在FreeNodeList为空需要生成新的MemBlock时。内存释放过程复杂度为O(1)。
boost::pool
boost::pool是内存池技术的变种。主要的变化如下:
MemBlock改为非固定长度(MemBlockSize),而是:第1次申请时m_nItemSize*32,第2次申请时 m_nItemSize*64,第3次申请时m_nItemSize*128,以此类推。不采用固定的MemBlockSize,而采用这种做法预测模型2,是一个细节上的改良。
增加了ordered_free(void* p) 函数。ordered_free区别于free的是,free把要释放的结点挂到自由内存链表(FreeNodeList)的开头, ordered_free则假设FreeNodeList是有序的,因此会遍历FreeNodeList把要释放的结点插入到合适的位置。我们已经看到,free的复杂度是O(1),非常快。但请注意ordered_free是比较费的操作,其复杂度是O(N)。这里N是FreeNodeList的大小。对于一个频繁释放/申请的系统,这个N很可能是个大数。这个boost描述得很清楚:http://www.boost.org/libs/pool/doc/interfaces/pool.html
注意:不要认为boost提供ordered_free是多此一举。后文我们会在讨论boost::object_pool时解释这一点。
基于内存池技术的通用内存分配组件
SGI STL把内存池(MemPool)技术进行发扬光大,用它来实现其最根本的allocator。
其大体的思想是,建立16个MemPool,<=8字节的内存申请由0号MemPool分配,<=16字节的内存申请由1号 MemPool分配,<=24字节的内存有2号MemPool分配,以此类推。最后,>128字节的内存申请由普通的malloc分配。
内存池技术的缺陷
遗憾的是,MemPool技术可能导致内存占用只增不减。还没有非常有效的办法去避免这种情况的发生。不过我后来在ScopeAlloc的实现中发现BlockPool(是一个简化版的内存池)反倒避免了这一缺陷。
注意
以上代码属于伪代码(struct _FreeNode、_MemBlock编译通不过),并且去除了出错处理。
Footnotes
1. boost:pool/object_pool 中称之为块(Chunk)。
2. 是的,这是一种用户内存需求的预测模型,其实std::vector的内存增长亦采用了该模型。
发表评论
-
FreeRTOS
2022-03-05 16:31 248Ref https://blog.csdn.net/weix ... -
串口通讯相关
2018-11-02 13:44 411https://bbs.csdn.net/wap/topics ... -
[转]C++验证IP是否可以PING通
2018-10-30 17:54 1325https://www.cnblogs.com/guoyz13 ... -
C++/MFC 換皮膚
2018-10-20 11:05 477https://blog.csdn.net/u01123991 ... -
WinCE 截屏 - C++ 代碼
2018-08-31 09:45 574// this function create a bmp ... -
Android NDK搭建環境
2017-11-27 13:25 580https://www.cnblogs.com/ut2016- ... -
8583协议相关
2017-10-17 13:38 5738583相关资料,整理中... -
Java高级应用之JNI
2017-06-19 09:00 600参考link http://www.cnblogs.com/l ... -
C++实现ping功能
2017-04-18 11:21 2155基础知识 ping的过程是向目的IP发送一个type=8的I ... -
OpenSSL 编译环境搭建
2017-03-27 15:01 9061 安裝VS2008到 c:\Program Files (x ... -
最优非对称加密填充(OAEP)
2017-03-25 14:53 1582OpenSSL命令---rsautl http://blog. ... -
[Platform Builder] 设置SVM OS build Env
2016-11-10 11:39 01 copy one OSDesign Project to ... -
[Windows] System Error Codes(GetLastError )0-----5999
2016-10-26 13:28 1881ERROR_SUCCESS 0 (0x0) T ... -
开源Windows驱动程序框架
2016-09-17 21:35 871转自 http://code.csdn.net/news/28 ... -
c/c++代码中执行cmd命令
2016-09-14 14:50 1908转自 http://blog.csdn.net/slixinx ... -
C#使用C++标准DLL实例(包含callback)
2016-09-11 19:44 1086C++编写标准Win32DLL如下 头文件 /***** ... -
C#调用C++的DLL搜集整理的所有数据类型转换方式
2016-09-09 16:07 969转自 http://www.cnblogs.com/zeroo ... -
WinCE CPU使用率计算 测试工具
2016-09-08 16:14 991转自 http://blog.csdn.net/jan ... -
switch在C++与C#中的一些差异
2016-09-08 15:19 810参考链接 http://blog.csdn.net/weiwe ... -
C++ 鼠标模拟程序
2016-09-04 12:09 1612转自 http://blog.csdn.net/weixinh ...
相关推荐
### 经典内存池技术详解 #### 一、引言 经典的内存池技术是一种高效的内存管理方式,尤其适用于需要频繁创建和销毁大量相同大小小对象的场景。它通过预分配和重用内存来减少内存分配与释放所带来的开销,从而显著...
`mempool` 提供了一种内存池的概念,它在程序启动时预先分配一大块内存,然后根据需求从这个内存池中分配小块内存,避免了频繁调用系统级别的内存分配函数,从而提高了性能。 内存池的基本原理是将大块内存分割成多...
### eCos内存管理详解 #### 引言 eCos(embedded Configurable Operating System)是一款用于嵌入式系统的可配置实时操作系统。它提供了丰富的内核功能和广泛的设备驱动支持,允许开发者根据具体应用需求定制系统...
#### 六、内存池库(Mempool Library) **6.1 Cookies** 这部分内容介绍了内存池库中的Cookies机制,类似于malloc库中的Cookies,用于记录附加信息。 **6.2 统计信息** 为了便于监控和调试,DPDK的内存池库提供了...
除了EAL,还有数据包处理库(Librte_Packet)和一致性内存管理库(Librte_Mempool)等,它们提供了高效的数据包处理和内存管理功能。 **5.3 DPDK 环境抽象层** EAL通过屏蔽底层硬件差异,使得DPDK库可以在多种平台...
### LwIP之内存及包缓冲管理详解 #### 一、概述 LwIP(Lightweight IP)是一款轻量级的TCP/IP协议栈,适用于资源有限的嵌入式系统。LwIP通过优化的设计和高效的内存管理机制,在有限的硬件资源上实现了完整的TCP/IP...
- **内存池管理(librte_mempool)**:负责高效地分配和回收固定大小的对象,减少了频繁调用系统内存管理函数所带来的开销。 - **网络报文缓冲区管理(librte_mbuf)**:管理着网络数据包的内存布局,每个报文都对应...
- **os_mempool.c**:内存池管理。 - **os_event.c**:信号量、互斥量和消息队列的实现。 - **os_flag.c**:标志组管理。 - **os_time.c**:时间管理,包括延时和定时器。 四、源码学习路径 1. **理解数据结构**:...
2. **cyg_mempool_destroy**:销毁内存池。当内存池不再需要时,可以通过此函数释放其占用的资源。 3. **cyg_mempool_alloc**:分配内存块。从内存池中分配一个内存块。 4. **cyg_mempool_free**:释放内存块。...
4. os_mempool.c:内存池管理的实现,包括内存分配和释放。 5. os_sem.c:信号量的创建、删除和操作函数。 6. os_msgq.c:消息队列的实现,用于任务间的数据传递。 7. os_timer.c:定时器功能的实现,包括周期性...
4. **Mempool**:内存池机制用于高效管理内存分配和释放,减少内存碎片。 5. **Core Bindings**:DPDK允许用户将CPU核心绑定到特定的网络接口,确保数据包处理在特定核上连续执行,避免多核间的通信开销。 6. **...
- **os_mempool.c**:内存池管理,分配和释放内存。 - **os_sem.c**、**os_msg.c**、**os_q.c**:信号量、消息队列和邮箱的实现。 通过深入学习和理解这些源码,开发者可以更好地利用uC/OS-II为嵌入式系统提供稳定...
同时,理解uC/OS-II的内存分配策略,如OS_Mem和OS_MemPool,以便有效利用内存。 2. **中断与任务切换**:中断服务不能直接访问任务级的数据,需通过信号量、邮箱等方式与任务通信。中断服务完成后,通过`...
- `void init_mempool(void *data *p, unsigned int size)`:初始化内存池。 - `void *malloc(unsigned int size)`:分配指定大小的内存。 - `int rand(void)`:生成随机数。 - `void *realloc(void xdata *p, ...
同时,"os_mempool.c"管理内存池,允许预先分配内存以提高效率。 四、信号量与互斥锁 UCOS2通过信号量和互斥锁实现资源的同步和保护。"os_sem.c"中的"OSSemCreate()"创建信号量,"OSSemPend()"和"OSSemPost()"分别...
23. **内存分配函数**:`kmalloc`用于小块内存分配,`__get_free_page`分配整页内存,`mempool_create`创建内存池。 24. **IRQ与FIQ**:IRQ是常规中断,FIQ是快速中断,MIPS等处理器中,FIQ通常用于高速数据传输或...
9. **Mempool**: 内存池技术,用于提高内存分配和释放的效率。 10. **Thrift**: 跨语言的服务定义和通信框架,Folly与Thrift有紧密的集成。 ### 使用Folly的益处 1. **提高代码质量**: Folly遵循最佳实践,使用...
5. os_mempool.c/h:内存池管理,用于动态分配和回收内存。 6. os_flag.c/h:事件标志组的操作函数。 7. os_mutext.c/h:互斥量的相关操作函数。 三、uCOSV251的安装与使用 1. 安装:提供的uCOSV251.exe文件是安装...
### SIMOTION V4.0 Web 诊断功能详解 #### 一、SIMOTION V4.0 Web 诊断功能概述 SIMOTION V4.0是西门子公司推出的一款高性能运动控制系统,其集成了Web诊断功能,允许用户通过标准浏览器访问SIMOTION CPU的信息。...