内存池完整实现代码及一些思考

简介: 为了提高效率和有效的监控内存的实时状态,我们采取了内存池的思想来解决效率与对内存实现监控的问题。 网上查找到了一些方案,根据自己的理解实现了应用。    我们什么时候要调用到内存池,    1,当我们频繁的申请释放同样数据大小的内存空间,我们可以用比动态new更有效方式来管理内存时,我们应该用内存池来提高效率。

为了提高效率和有效的监控内存的实时状态,我们采取了内存池的思想来解决效率与对内存实现监控的问题。

网上查找到了一些方案,根据自己的理解实现了应用。

   我们什么时候要调用到内存池,

   1,当我们频繁的申请释放同样数据大小的内存空间,我们可以用比动态new更有效方式来管理内存时,我们应该用内存池来提高效率。

   2,当我们需要知道内存实时的申请状态,以便于对于服务器内存状态做实时预警时,我们可以用内存池的接口,来给内存增加监控。

 

实现的特点:

   1,内存池内存单元大小可以动态定义,实现多级内存池。

   2,申请效率很高,单元测试下是普通new/delete的4倍左右,当然具体性能还应机器类别而异。

   

 

MemoryPool.h 的实现

 

//该内存池理论来自于IBM文章,http://www.ibm.com/developerworks/cn/linux/l-cn-ppp/index6.html
//作者冯宏华,徐莹,程远,汪磊享有论文著作权,由2011-06-06 konyel lin根据相关代码和理论进行优化修改。

#include <string>
#include <malloc.h>
//内存对齐值,可以根据机器取指长度进行设置
#define MEMPOOL_ALIGNMENT 4

#define USHORT unsigned short
#define ULONG unsigned long

struct MemoryBlock
{
  USHORT nSize;
  USHORT nFree;
  USHORT nFirst;
  USHORT nDummyAlign1;
  MemoryBlock* pNext;
  char aData[1];
  static void* operator new(size_t,USHORT nTypes, USHORT nUnitSize){
     return ::operator new(sizeof(MemoryBlock) + nTypes * nUnitSize);
  }
  static void operator delete(void *p, size_t){
      ::operator delete (p);
  }
  MemoryBlock (USHORT nTypes = 1, USHORT nUnitSize = 0);
  ~MemoryBlock() {}
};

class MemoryPool
{
   private:
   MemoryBlock* pBlock;
   USHORT nUnitSize;
   USHORT nInitSize;
   USHORT nGrowSize;
   public:
   MemoryPool( USHORT nUnitSize,
   USHORT nInitSize = 1024,
   USHORT nGrowSize = 256 );
   ~MemoryPool();
   void* Alloc();
   void Free( void* p );
};

 

 

MemoryPool.cpp 的实现

 

#include "MemoryPool.h"

MemoryPool::MemoryPool( USHORT _nUnitSize,
USHORT _nInitSize, USHORT _nGrowSize )
{
  pBlock = NULL;
  nInitSize = _nInitSize;
  nGrowSize = _nGrowSize;
  if ( _nUnitSize > 4 ) 

  nUnitSize = (_nUnitSize + (MEMPOOL_ALIGNMENT-1)) & ~(MEMPOOL_ALIGNMENT-1);
  else if ( _nUnitSize <= 2 )
  nUnitSize = 2;
  else
  nUnitSize = 4;
}

void* MemoryPool::Alloc()
{
  MemoryBlock* pMyBlock;
  if ( !pBlock ){
     //第一次调用初始化内存块
     pMyBlock =new(nGrowSize, nUnitSize) MemoryBlock(nGrowSize, nUnitSize);
     pBlock = pMyBlock;
      return (void*)(pMyBlock->aData);
  }
  pMyBlock = pBlock;
  while (pMyBlock && !pMyBlock->nFree )
    pMyBlock = pMyBlock->pNext;
  if ( pMyBlock ){
    printf("get a mem from block/n");
    char* pFree = pMyBlock->aData+(pMyBlock->nFirst*nUnitSize);
    //aData记录实际的内存单元标识
    pMyBlock->nFirst = *((USHORT*)pFree);
    pMyBlock->nFree--;
    return (void*)pFree;
  }
  else{
    printf("add a new block/n");
    if (!nGrowSize)
    return NULL;
    pMyBlock = new(nGrowSize, nUnitSize) MemoryBlock(nGrowSize, nUnitSize);
    if (!pMyBlock )
    return NULL;
    pMyBlock->pNext = pBlock;
    pBlock = pMyBlock;
    return (void*)(pMyBlock->aData);
  }
}


void MemoryPool::Free( void* pFree ){
  MemoryBlock* pMyBlock = pBlock;
  MemoryBlock* preMyBlock;
  //确定该待回收分配单元(pFree)落在哪一个内存块的指针范围内,大于起始节点,小于终止节点。
  while ( ((ULONG)pMyBlock->aData > (ULONG)pFree) ||
  ((ULONG)pFree >= ((ULONG)pMyBlock->aData + pMyBlock->nSize))){
    //不在内存块范围内,则历遍下一个节点
    preMyBlock=pMyBlock;
    pMyBlock=pMyBlock->pNext;
  }
  pMyBlock->nFree++;
  *((USHORT*)pFree) = pMyBlock->nFirst;
  pMyBlock->nFirst = (USHORT)(((ULONG)pFree-(ULONG)(pBlock->aData)) / nUnitSize);
  //判断内存块是否全部为自由状态,是则释放整个内存块
  if (pMyBlock->nFree*nUnitSize == pMyBlock->nSize ){
     preMyBlock->pNext=pMyBlock->pNext;
     delete pMyBlock;
  }
}

MemoryBlock::MemoryBlock (USHORT nTypes, USHORT nUnitSize)
: nSize (nTypes * nUnitSize),
    nFree (nTypes - 1),
  nFirst (1),
  pNext (0)
{
  char * pData = aData;
  for (USHORT i = 1; i < nTypes; i++) {
    //将内存块的前2个字节用来存放内存单元的标识
    *reinterpret_cast<USHORT*>(pData) = i;
    pData += nUnitSize;
  }
}

目录
相关文章
|
存储 缓存 Java
优化Java代码中的内存使用:使用WeakHashMap解决内存泄漏问题
在Java应用程序中,内存泄漏是一个常见的问题,尤其是在处理大量对象时。本文将介绍如何使用WeakHashMap数据结构来解决内存泄漏问题,通过示例代码演示其在实际项目中的应用,从而提高Java代码的性能和可靠性。
|
3月前
|
安全 Java 应用服务中间件
Spring Boot + Java 21:内存减少 60%,启动速度提高 30% — 零代码
通过调整三个JVM和Spring Boot配置开关,无需重写代码即可显著优化Java应用性能:内存减少60%,启动速度提升30%。适用于所有在JVM上运行API的生产团队,低成本实现高效能。
334 3
|
3月前
|
存储 大数据 Unix
Python生成器 vs 迭代器:从内存到代码的深度解析
在Python中,处理大数据或无限序列时,迭代器与生成器可避免内存溢出。迭代器通过`__iter__`和`__next__`手动实现,控制灵活;生成器用`yield`自动实现,代码简洁、内存高效。生成器适合大文件读取、惰性计算等场景,是性能优化的关键工具。
252 2
|
SQL 关系型数据库 MySQL
实时计算 Flink版产品使用合集之idea本地测试代码,要增大 Flink CDC 在本地 IDEA 测试环境中的内存大小如何解决
实时计算Flink版作为一种强大的流处理和批处理统一的计算框架,广泛应用于各种需要实时数据处理和分析的场景。实时计算Flink版通常结合SQL接口、DataStream API、以及与上下游数据源和存储系统的丰富连接器,提供了一套全面的解决方案,以应对各种实时计算需求。其低延迟、高吞吐、容错性强的特点,使其成为众多企业和组织实时数据处理首选的技术平台。以下是实时计算Flink版的一些典型使用合集。
275 1
|
存储 C++
webserver--Buffer类实现内存缓冲区读写(全代码)
webserver--Buffer类实现内存缓冲区读写(全代码)
|
存储 算法 Java
Java 内存管理与优化:掌控堆与栈,雕琢高效代码
Java内存管理与优化是提升程序性能的关键。掌握堆与栈的运作机制,学习如何有效管理内存资源,雕琢出更加高效的代码,是每个Java开发者必备的技能。
285 5
|
并行计算 算法 测试技术
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面,旨在通过综合策略提升程序性能,满足实际需求。
441 1
|
11月前
|
安全 测试技术 数据库
代码危机:“内存溢出” 事件的深度剖析与反思
初涉编程时,我坚信严谨逻辑能让代码顺畅运行。然而,“内存溢出”这一恶魔却以残酷的方式给我上了一课。在开发电商平台订单系统时,随着订单量增加,系统逐渐出现处理迟缓甚至卡死的情况,最终排查发现是订单状态更新逻辑中的细微错误导致内存无法及时释放,进而引发内存溢出。这次经历让我深刻认识到微小错误可能带来巨大灾难,从此对待代码更加谨慎,并养成了定期审查和测试的习惯。
164 0
|
存储 JavaScript 前端开发
如何优化代码以避免闭包引起的内存泄露
本文介绍了闭包引起内存泄露的原因,并提供了几种优化代码的策略,帮助开发者有效避免内存泄露问题,提升应用性能。
|
存储 缓存 JSON
一行代码,我优化掉了1G内存占用
这里一行代码,指的是:String.intern()的调用,为了调用这一行代码,也写了几十行额外的代码。