内存池的设计和实现总结(一)
C/C++下内存管理是让几乎每一个程序员头疼的问题,分配足够的内存、追踪内存的分配、在不需要的时候释放内存——这个任务相当复杂。而直接使用系统调用malloc/free、new/delete进行内存分配和释放,有以下弊端:
- 调用malloc/new,系统需要根据“最先匹配”、“最优匹配”或其他算法在内存空闲块表中查找一块空闲内存,调用free/delete,系统可能需要合并空闲内存块,这些会产生额外开销
- 频繁使用时会产生大量内存碎片,从而降低程序运行效率
- 容易造成内存泄漏
1 #pragma once 2 3 //开发一个简单的内存池,用于内存管理。 4 5 #include <stdio.h> 6 #include <stdlib.h> 7 #include <list> 8 #include "ThreadLock.h" 9 10 #define MAX_MEMORYHEAD_SIZE 12 //4个字节的指针块地址 + 4个字节的List表首地址 + 4位验证码 11 #define MAGIC_CODE 0xFFFFFF //验证码 12 #define MEMORY_BUFFER_SIZE 1024 //该简单的内存池,提供1024字节大小的内存块 13 #define UINT32 unsigned int 14 15 struct _MemoryBlock //内存块的结构,12字节head+内存空间 16 { 17 void* m_pBrick; 18 _MemoryBlock() 19 { 20 m_pBrick = NULL; 21 }; 22 }; 23 24 25 class CSingleMemoryPools 26 { 27 public: 28 static CSingleMemoryPools& Instance() 29 { 30 if(m_pMemoryPools == NULL) 31 { 32 m_pMemoryPools = new CSingleMemoryPools(); 33 } 34 35 return *m_pMemoryPools; 36 } 37 38 public: 39 ~CSingleMemoryPools(void); 40 41 void* GetBuff(); 42 bool DelBuff(void* pBuff); 43 void DisplayMemoryList(); 44 45 private: 46 CSingleMemoryPools(void); 47 void Close(); 48 void* SetMemoryHead(void* pBuff, std::list<_MemoryBlock*>* pList, _MemoryBlock* pBlock); 49 void* GetMemoryHead(void* pBuff); 50 bool GetHeadMemoryBlock(void* pBuff, std::list<_MemoryBlock*>*& pList, _MemoryBlock*& pBlock); 51 52 private: 53 static CSingleMemoryPools* m_pMemoryPools; 54 std::list<_MemoryBlock*> m_pMemoryFreeList; //自由的内存块list 55 CThreadLock m_ThreadLock; 56 };
1 #include "SingleMemoryPools.h" 2 #include <iostream> 3 4 CSingleMemoryPools* CSingleMemoryPools::m_pMemoryPools = NULL; 5 CSingleMemoryPools::CSingleMemoryPools(void) 6 { 7 8 } 9 10 CSingleMemoryPools::~CSingleMemoryPools(void) 11 { 12 Close(); 13 } 14 15 16 void CSingleMemoryPools::Close() 17 { 18 //添加线程安全 19 CAutoLock autolock(&m_ThreadLock); 20 21 //删除所有已经归还的内存块, 22 //注:这个简单的内存池功能,关闭功能必须在所有分配出去的内存块都还回来之后才可以Close 23 24 std::list<_MemoryBlock*>::iterator itor = m_pMemoryFreeList.begin(); 25 while(itor != m_pMemoryFreeList.end()) 26 { 27 free((*itor)->m_pBrick); 28 m_pMemoryFreeList.erase(itor); 29 //兼容linux环境,linux下没有iterator erase( iterator _Where )方法, 有void erase( iterator _Where )方法 30 itor = m_pMemoryFreeList.begin(); 31 } 32 } 33 34 void* CSingleMemoryPools::SetMemoryHead(void* pBuff, std::list<_MemoryBlock*>* pList, _MemoryBlock* pBlock) 35 { 36 //组成内存包头 37 if(NULL == pBuff) 38 { 39 return NULL; 40 } 41 42 //因为一个long是4个字节,在linux和windows下都是一样的。所以加起来是12个 43 UINT32* plData = (UINT32*)pBuff; 44 45 plData[0] = (UINT32)pList; //内存List表首地址 46 plData[1] = (UINT32)pBlock; //所在链表的地址 47 plData[2] = (UINT32)MAGIC_CODE; //验证码 48 49 return &plData[3]; 50 } 51 52 void* CSingleMemoryPools::GetMemoryHead(void* pBuff) 53 { 54 if(NULL == pBuff) 55 { 56 return NULL; 57 } 58 59 long* plData = (long*)pBuff; 60 return &plData[3]; 61 } 62 63 bool CSingleMemoryPools::GetHeadMemoryBlock(void* pBuff, std::list<_MemoryBlock*>*& pList, _MemoryBlock*& pBlock) 64 { 65 char* szbuf = (char*)pBuff; 66 UINT32* plData = (UINT32*)(szbuf - MAX_MEMORYHEAD_SIZE); 67 if(plData[2] != (long)MAGIC_CODE) 68 { 69 return false; 70 } 71 else 72 { 73 pList = (std::list<_MemoryBlock*>*)plData[0]; //内存List表首地址 74 pBlock = (_MemoryBlock*)plData[1]; //所在链表的地址 75 76 return true; 77 } 78 79 } 80 81 void* CSingleMemoryPools::GetBuff() 82 { 83 //添加线程安全 84 CAutoLock autolock(&m_ThreadLock); 85 86 void* pBuff = NULL; 87 88 //判断是否有空闲的内存块。 89 if(m_pMemoryFreeList.empty()) 90 { 91 //申请内存块空间 92 pBuff = malloc(MEMORY_BUFFER_SIZE + MAX_MEMORYHEAD_SIZE); 93 memcpy(pBuff,0,MEMORY_BUFFER_SIZE + MAX_MEMORYHEAD_SIZE); 94 if(NULL == pBuff) 95 { 96 //printf_s("[CSingleMemoryPools::GetBuff] pBuff malloc = NULL.\n"); 97 return NULL; 98 } 99 100 //新建一个内存块单元 101 _MemoryBlock* pMemoryUsed = new _MemoryBlock(); 102 if(NULL == pMemoryUsed) 103 { 104 //printf_s("[CSingleMemoryPools::GetBuff] pMemoryBrick new = NULL.\n"); 105 delete pBuff; 106 return NULL; 107 } 108 109 pMemoryUsed->m_pBrick = pBuff; 110 return SetMemoryHead(pBuff, &m_pMemoryFreeList, pMemoryUsed); 111 } 112 113 //已有空余内存块,由于内存块头部已经初始化过了,这边无须再初始化,直接扔出来就可以了 114 _MemoryBlock* pBlockBuff = (m_pMemoryFreeList.front()); 115 m_pMemoryFreeList.pop_front(); 116 return GetMemoryHead(pBlockBuff->m_pBrick); 117 } 118 119 bool CSingleMemoryPools::DelBuff(void* pBuff) 120 { 121 //添加线程安全 122 CAutoLock autolock(&m_ThreadLock); 123 124 _MemoryBlock* pMemoryUsed = NULL; 125 std::list<_MemoryBlock*>* pCurrMemoryList = NULL; 126 127 if(false == GetHeadMemoryBlock(pBuff, pCurrMemoryList, pMemoryUsed)) 128 { 129 return false; 130 } 131 132 if(NULL != pMemoryUsed && pCurrMemoryList == &m_pMemoryFreeList ) 133 { 134 m_pMemoryFreeList.push_back(pMemoryUsed); 135 return true; 136 } 137 138 //printf_s("[CSingleMemoryPools::DelBuff] pBuff = 0x%08x is not memoryPool.\n", pBuff); 139 return false; 140 } 141 142 void CSingleMemoryPools::DisplayMemoryList() 143 { 144 int nFreeCount = m_pMemoryFreeList.size(); 145 printf_s("[CSingleMemoryPools::DisplayMemoryList] pMemoryFree nFreeCount = %d, Size = %d.\n", nFreeCount, MEMORY_BUFFER_SIZE * nFreeCount); 146 } 147 148 // TODO: 在 STDAFX.H 中 149 // 引用任何所需的附加头文件,而不是在此文件中引用 150 //#include "MemoryPools.h" 151 152 //重载New和Delete操作符 153 inline void* operator new(size_t szBuff) 154 { 155 //注:由于这是一个简单的内存池,大小固定,所以参数szBuff没有用起来,后期会开发一个多层级大小的内存池 156 void* pBuff = CSingleMemoryPools::Instance().GetBuff(); 157 //OUR_DEBUG((LM_ERROR, "[New] Size = %d Address = [0x%08x].!\n", (int)szBuff, pBuff)); 158 return pBuff; 159 } 160 161 inline void operator delete(void* p) 162 { 163 if(false == CSingleMemoryPools::Instance().DelBuff(p)) 164 { 165 // OUR_DEBUG((LM_ERROR, "[Delete]*p = [0x%08x] false!\n", p)); 166 //CSingleMemoryPools::Instance().DisplayMemoryList(p); 167 } 168 else 169 { 170 //OUR_DEBUG((LM_ERROR, "[Delete]*p = [0x%08x] OK!\n", p)); 171 } 172 } 173 174 inline void operator delete[]( void * p ) 175 { 176 if(false == CSingleMemoryPools::Instance().DelBuff(p)) 177 { 178 // OUR_DEBUG((LM_ERROR, "[Delete]*p = [0x%08x] false!\n", p)); 179 //CSingleMemoryPools::Instance().DisplayMemoryList(p); 180 } 181 else 182 { 183 //OUR_DEBUG((LM_ERROR, "[Delete]*p = [0x%08x] OK!\n", p)); 184 } 185 }
使用一个list来管理内存,相对于用两个list(一个FreeList ,一个 Used List)的优点:更加简洁,管理更加简单;缺陷:无法知晓已经分配出去的内存块。
转载于:https://www.cnblogs.com/pilipalajun/p/5418286.html
内存池的设计和实现总结(一)相关推荐
- Netty---论内存池源设计的巧妙
一.整体内存池架构设计 顶层使用allocator分配内存,类似门面模式,将内存分配真正交给对应的arena. 二.PooledByteBufAllocator.Arena的创建 PooledByte ...
- 性能优化-高效内存池的设计与实现
原文地址: 高效内存池的设计与实现 关注公众号[高性能架构探索],也可以后台回复[pdf],获取计算机必备经典书籍 大家好,我是雨乐! 在之前的文章中,我们分析了glibc内存管理相关的内容,里面的是 ...
- Nginx源码阅读笔记-内存池的设计
2019独角兽企业重金招聘Python工程师标准>>> nginx的内存池设计的比较简单了,一个内存池中分为两个部分: 超过max大小的内存分配,走大块内存分配,这部分内存管理由ng ...
- 嵌入式操作系统内核原理和开发(等值block内存池设计)
[ 声明:版权所有,欢迎转载,请勿用于商业用途. 联系信箱:feixiaoxing @163.com] 内存池设计是嵌入式系统的一个重要环节,之前我们也讨论过相关的内容.但是,看了r ...
- C 实现高性能内存池
版权 一.概述 在 C/C 中,内存管理是一个非常棘手的问题,我们在编写一个程序的时候几乎不可避免的要遇到内存的分配逻辑,这时候随之而来的有这样一些问题:是否有足够的内存可供分配? 分配失败了怎么办? ...
- 内存池(memory pool)
前言 通常的进程发起申请内存的动作之后,会在系统的空闲内存区寻找合适大小的内存块(底层分配函数__alloc_node_mask),如果满足就直接分配,如果不满足就会向上查找.如果过大就会进行分裂,一 ...
- Wireshark----wmem 内存池、内存管理的学习--README.wmem 翻译
1. 什么是内存池? 当创建大量消耗小内存的对象时,频繁调用new/malloc会导致大量的内存碎片,致使效率降低.内存池的概念就是预先在内存中申请一定数量的,大小相等 的内存块留作备用,当有新的内存 ...
- c++——内存池介绍
1.默认内存管理函数的不足 利用默认的内存管理操作符new/delete和函数malloc()/free()在堆上分配和释放内存会有一些额外的开销. 系统在接收到分配一定大小内存的请求时,首先查找内部 ...
- Nginx 内存池剖析
Nginx 内存池剖析 为什么要使用 Nginx 内存池 传统直接调用内存分配函数的弊端 弊端的解决之道 什么是Nginx 内存池 什么是内存池技术 内存池如何解决弊端 内存池的设计思想 分而治之 N ...
最新文章
- 别瞎操心了!机器人根本不会抢你的饭碗
- springmvc笔记(1)—使用maven快速构建springmvc项目
- MySQL内核:InnoDB存储引擎 卷1
- OS / Linux / 伙伴(buddy)算法
- 原创-互联网技术图谱
- 利用Android中的三大主件来实现一个码表
- 你的专属云资源管家!阿里云正式对外发布云解析PrivateZone!
- 73页PPT,教你从0到1构建用户画像系统(附下载)
- 寻找点赞所需的URL
- python伪装浏览器https_Python3 伪装浏览器的方法示例
- 软件工程--软件详细设计说明书(免费小说网站)
- 新站快速排名的seo优化流程
- 初步设计对复杂系统的意义
- 【C#】Activator.CreateInstance用法
- 深度体验中国长城2020版笔记本电脑有感
- 算法工程师与java_java算法工程师的职责是什么?前景如何?
- QCOM 8976 porting SPI device
- 输入任意字符,若是小写则变为大写字母,否则原样输出
- 物理隔离与数据交换-网闸的设计原理与误区
- 论文篇------交通常识
热门文章
- AtCoder Beginner Contest 185
- 两个正数相乘为什么结果是负数
- c语言系统关键词有哪些,C语言的那些关键字
- employees mysql_「employees」mysql示例employees数据库 - seo实验室
- python ssl模块安装_在Windows上安装Python的SSL模块(2.5.4)
- RDLC报表显示存储于数据库的图片
- Hibernate框架基本使用
- Hammer.js分析(四)——recognizer.js
- Revit Family API 添加几何实体
- /31位掩码实验演示