C/C++下内存管理是让几乎每一个程序员头疼的问题,分配足够的内存、追踪内存的分配、在不需要的时候释放内存——这个任务相当复杂。而直接使用系统调用malloc/free、new/delete进行内存分配和释放,有以下弊端:

  1. 调用malloc/new,系统需要根据“最先匹配”、“最优匹配”或其他算法在内存空闲块表中查找一块空闲内存,调用free/delete,系统可能需要合并空闲内存块,这些会产生额外开销
  2. 频繁使用时会产生大量内存碎片,从而降低程序运行效率
  3. 容易造成内存泄漏
内存池则是在真正使用内存之前,先申请分配一定数量的、大小相等(一般情况下)的内存块留作备用。当有新的内存需求时,就从内存池中分出一部分内存块,若内存块不够再继续申请新的内存。这样做的一个显著优点是,使得内存分配效率得到提升。
本章先实现一个简单的内存池(CSingleMemoryPools)。该内存池提供一定数量、大小相等的内存块。该实例中,CSingleMemoryPools中的m_pMemoryFreeList负责对空闲内存块进行管理,每个内存块以_MemoryBlock类进行管理,其中首部有4个字节的指针块地址 + 4个字节的list表首地址 + 4位验证码,然后才是分配的内存。
 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

内存池的设计和实现总结(一)相关推荐

  1. Netty---论内存池源设计的巧妙

    一.整体内存池架构设计 顶层使用allocator分配内存,类似门面模式,将内存分配真正交给对应的arena. 二.PooledByteBufAllocator.Arena的创建 PooledByte ...

  2. 性能优化-高效内存池的设计与实现

    原文地址: 高效内存池的设计与实现 关注公众号[高性能架构探索],也可以后台回复[pdf],获取计算机必备经典书籍 大家好,我是雨乐! 在之前的文章中,我们分析了glibc内存管理相关的内容,里面的是 ...

  3. Nginx源码阅读笔记-内存池的设计

    2019独角兽企业重金招聘Python工程师标准>>> nginx的内存池设计的比较简单了,一个内存池中分为两个部分: 超过max大小的内存分配,走大块内存分配,这部分内存管理由ng ...

  4. 嵌入式操作系统内核原理和开发(等值block内存池设计)

    [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com]         内存池设计是嵌入式系统的一个重要环节,之前我们也讨论过相关的内容.但是,看了r ...

  5. C 实现高性能内存池

    版权 一.概述 在 C/C 中,内存管理是一个非常棘手的问题,我们在编写一个程序的时候几乎不可避免的要遇到内存的分配逻辑,这时候随之而来的有这样一些问题:是否有足够的内存可供分配? 分配失败了怎么办? ...

  6. 内存池(memory pool)

    前言 通常的进程发起申请内存的动作之后,会在系统的空闲内存区寻找合适大小的内存块(底层分配函数__alloc_node_mask),如果满足就直接分配,如果不满足就会向上查找.如果过大就会进行分裂,一 ...

  7. Wireshark----wmem 内存池、内存管理的学习--README.wmem 翻译

    1. 什么是内存池? 当创建大量消耗小内存的对象时,频繁调用new/malloc会导致大量的内存碎片,致使效率降低.内存池的概念就是预先在内存中申请一定数量的,大小相等 的内存块留作备用,当有新的内存 ...

  8. c++——内存池介绍

    1.默认内存管理函数的不足 利用默认的内存管理操作符new/delete和函数malloc()/free()在堆上分配和释放内存会有一些额外的开销. 系统在接收到分配一定大小内存的请求时,首先查找内部 ...

  9. Nginx 内存池剖析

    Nginx 内存池剖析 为什么要使用 Nginx 内存池 传统直接调用内存分配函数的弊端 弊端的解决之道 什么是Nginx 内存池 什么是内存池技术 内存池如何解决弊端 内存池的设计思想 分而治之 N ...

最新文章

  1. 别瞎操心了!机器人根本不会抢你的饭碗
  2. springmvc笔记(1)—使用maven快速构建springmvc项目
  3. MySQL内核:InnoDB存储引擎 卷1
  4. OS / Linux / 伙伴(buddy)算法
  5. 原创-互联网技术图谱
  6. 利用Android中的三大主件来实现一个码表
  7. 你的专属云资源管家!阿里云正式对外发布云解析PrivateZone!
  8. 73页PPT,教你从0到1构建用户画像系统(附下载)
  9. 寻找点赞所需的URL
  10. python伪装浏览器https_Python3 伪装浏览器的方法示例
  11. 软件工程--软件详细设计说明书(免费小说网站)
  12. 新站快速排名的seo优化流程
  13. 初步设计对复杂系统的意义
  14. 【C#】Activator.CreateInstance用法
  15. 深度体验中国长城2020版笔记本电脑有感
  16. 算法工程师与java_java算法工程师的职责是什么?前景如何?
  17. QCOM 8976 porting SPI device
  18. 输入任意字符,若是小写则变为大写字母,否则原样输出
  19. 物理隔离与数据交换-网闸的设计原理与误区
  20. 论文篇------交通常识

热门文章

  1. AtCoder Beginner Contest 185
  2. 两个正数相乘为什么结果是负数
  3. c语言系统关键词有哪些,C语言的那些关键字
  4. employees mysql_「employees」mysql示例employees数据库 - seo实验室
  5. python ssl模块安装_在Windows上安装Python的SSL模块(2.5.4)
  6. RDLC报表显示存储于数据库的图片
  7. Hibernate框架基本使用
  8. Hammer.js分析(四)——recognizer.js
  9. Revit Family API 添加几何实体
  10. /31位掩码实验演示