一个及其简化版本的内存池实现

最近写的一个程序中需要频繁的申请和释放零碎的内存块,这些内存块的大小却只有简单的几种。如果直接使用系统调用malloc/free、new/delete进行内存分配和释放,则效率很低。程序运行时间长了会产生大量的内存碎片。想起uC/OS-II 里面提供了个内存分配单元,正好满足我的需要。就把里面相关的代码扒了出来。写成了一个内存池的类。

这个内存池的功能非常的简单,初始化时分配一大块内存,然后将各个小内存块串成一个单项链表。每次分配内存块时从链表的头上去取一个内存块。回收内存块时也是将内存块插到链表的开头处。

这个类的结构如下:

#ifndef MEMPOOL_H
#define MEMPOOL_H

#define MEM_NO_ERR          0
#define MEM_INVALID_ADDR    1
#define MEM_INVALID_BLKS    2
#define MEM_INVALID_SIZE    3
#define MEM_INVALID_PART    4
#define MEM_INVALID_PBLK    5
#define MEM_FULL            6
class MemPool
{
public:
	MemPool();
	~MemPool();
    int create (int nblocks, unsigned int blocksize);
    void* get( void );
    int release ( void *pblk );
    int blocks( void ) const {return m_memNBlks;};
    int frees( void ) const {return m_memNFree;};
private:
    char *m_memAddr; /* Pointer to beginning of memory partition */
    char *m_memFreeList; /* Pointer to list of free memory blocks */
    int m_memBlkSize; /* Size (in bytes) of each block of memory */
    int m_memNBlks; /* Total number of blocks in this partition */
    int m_memNFree; /* Number of memory blocks remaining in this */
};

#endif

create 函数初始化内存池。主要的工作就是分配内存,然后将内存块串起来形成一个链表。因为要用指针形成链表,因此要求内存块的大小至少要能容纳一个指针。

get 函数获得一个内存块,如果没有剩余的内存块了,就返回 null。

release 函数回收内存块。

blocks 函数返回内存池总共有多少内存块。

frees 函数返回内存池还剩多少剩余的内存块。

代码实现如下:

#include <stddef.h>
#include "MemPool.h"

MemPool::MemPool()
{
    m_memAddr = NULL;
    m_memFreeList = NULL;
    m_memBlkSize = 0;
    m_memNBlks = 0;
    m_memNFree = 0;
}
MemPool::~MemPool()
{
    if(m_memAddr != NULL)
    {
        delete [] m_memAddr;
    }
}
int MemPool::create ( int nblks, unsigned int blksize )
{
    if( m_memAddr != NULL )
    {
        delete [] m_memAddr;
    }
    m_memAddr = new char[nblks * blksize];
    if ( m_memAddr == NULL )
    {
        return MEM_INVALID_ADDR;
    }
    if ( nblks < 2 )
    {
        /* Must have at least 2 blocks per partition */
        return MEM_INVALID_BLKS;
    }

    if ( blksize < sizeof(void *) )
    {
        /* Must contain space for at least a pointer */
        return MEM_INVALID_SIZE;
    }
    void ** p = (void **)m_memAddr;
    char *pblk = m_memAddr + blksize;
    for (int i = 0; i < (nblks - 1); i++)
    {
        *p = (void *) pblk;
        p = (void **) pblk;
        pblk   = pblk + blksize;
    }
    *p = (void *)0;

    m_memFreeList = m_memAddr;
    m_memNBlks = nblks;
    m_memNFree = nblks;
    return MEM_NO_ERR;
}

void * MemPool::get( void )
{
    void *pblk;
    if (m_memNFree > 0)
    {
        /* See if there are any free memory blocks */
        pblk = m_memFreeList;    /* Yes, point to next free memory block */
        m_memFreeList = (char *) *(void **)pblk; /* Adjust pointer to new free list */
        m_memNFree--;/* One less memory block in this partition  */
        return (pblk); /* Return memory block to caller */
    }
    return ((void *)0);
}
int MemPool::release ( void *pblk )
{
    if (pblk == (void *)0)
    {
        /* Must release a valid block */
        return (MEM_INVALID_PBLK);
    }
    if (m_memNFree >= m_memNBlks)
    {
        /* Make sure all blocks not already returned */
        return (MEM_FULL);
    }
    /* Insert released block into free block list */
    *(void **)pblk = m_memFreeList;
    m_memFreeList = (char *) pblk;

    m_memNFree++; /* One more memory block in this partition */
    return (MEM_NO_ERR); /* Notify caller that memory block was released */
}

下面是个简答的测试代码:

#include <iostream>
#include "MemPool.h"
using namespace std;
typedef struct
{
    unsigned char *ImageData;
    int SizeX;
    int SizeY;
    int ImageID;
    double Timestamp;
    double TransferTime;
    unsigned int PacketCount;
}IMAGE_INFO;

int main()
{
    IMAGE_INFO * p[15];
    MemPool mem;
    mem.create(15, sizeof(IMAGE_INFO));

    for(int i = 0; i < 10; i++)
    {
        p[i] = (IMAGE_INFO *)mem.get();
        cout << "p[" << i << "] addr = " << p[i] << endl;
        p[i]->SizeX = i;
        p[i]->SizeY = i;
    }
    for(int i = 1; i < 10; i++)
    {
        cout << "p[" << i << "]->SizeX = " << p[i]->SizeX << endl;
        mem.release(p[i]);
    }
    cout << "mem.blocks()" << mem.blocks() << endl;
    cout << "mem.frees()" << mem.frees() << endl;
    return 0;
}

这个测试程序的运行结果如下:

p[0] addr = 0xac1358
p[1] addr = 0xac1380
p[2] addr = 0xac13a8
p[3] addr = 0xac13d0
p[4] addr = 0xac13f8
p[5] addr = 0xac1420
p[6] addr = 0xac1448
p[7] addr = 0xac1470
p[8] addr = 0xac1498
p[9] addr = 0xac14c0
p[1]->SizeX = 1
p[2]->SizeX = 2
p[3]->SizeX = 3
p[4]->SizeX = 4
p[5]->SizeX = 5
p[6]->SizeX = 6
p[7]->SizeX = 7
p[8]->SizeX = 8
p[9]->SizeX = 9
mem.blocks()15
mem.frees()14

最后多说一句,如果程序中多个线程要访问同一个内存池,那个需要给 get 和 release 函数加锁。

另外,这个代码其实可以用C++的模版类来实现。等我有空了就写一个。

时间: 2024-08-30 03:44:02

一个及其简化版本的内存池实现的相关文章

一个非常简单的C++内存池方案

在游戏中频繁使用new与delete将会导致性能的下降,还可能造成内存碎片. 使用以一个自定义的内存分配器将是很重要的. 创建一个通用又强大效率性能又高的内存分配器将是困难的,所以这个的分配器面向下面的情况使用: 1. 一开始就就申请,直到游戏退出才释放 这种情况我们无需做分配器内部的内存释放,仅需将分配器本身释放掉即可 2. 申请后立即释放 当然不算是立即释放,不然就没用了. 这种情况一般是需要一个临时缓冲区,或者使用一个临时对象. 我们的内存可以记录上次申请的情况,方便重复利用内存资源. 当

【源码剖析】MemoryPool —— 简单高效的内存池 allocator 实现

什么是内存池?什么是 C++ 的 allocator? 内存池简单说,是为了减少频繁使用 malloc/free new/delete 等系统调用而造成的性能损耗而设计的.当我们的程序需要频繁地申请和释放内存时,频繁地使用内存管理的系统调用可能会造成性能的瓶颈,嗯,是可能,毕竟操作系统的设计也不是盖的(麻麻说把话说太满会被打脸的(⊙v⊙)).内存池的思想是申请较大的一块内存(不够时继续申请),之后把内存管理放在应用层执行,减少系统调用的开销. 那么,allocator 呢?它默默的工作在 C++

boost内存池的使用介绍

Boost库的pool提供了一个内存池分配器,用于管理在一个独立的.大的分配空间里的动态内存分配. Boost库的pool主要适用于快速分配同样大小的内存块,尤其是反复分配和释放同样大小的内存块的情况.使用pool内存池主要有以下两个优点: 1. 能够有效地管理许多小型对象的分配和释放工作,避免了自己去管理内存而产生的内存碎片和效率低下问题. 2.  告别程序内存泄漏的烦恼,pool库会在内部对内存自动进行管理,避免了程序员一不小心而造成的内存泄漏问题. pool库主要提供了四种内存池接口,分别

一个简易内存池(C++)

做这个内存池主要是为了完成一道面试题,题目在代码中. 代码 1 #include <iostream> 2 #include<string> 3 #include <list> 4 using namespace std; 5 6 //一个简单的内存池,池中保存3块内存分别为1k,2k,4k 7 //实现池子的malloc(size)和free(void*)操作 8 //不考虑跨块申请内存情况 9 10 class node 11 { 12 public: 13 int

一个依靠STL vector的接口进行申请和回收管理的内存池类( c++ 封装)

其他出现两次,只有一个出现一次的那道题我就不更了,直接抑或,最后的结果就是那个数.为什么可以这样做呢?因为一个32位int,如果所有数都出现了两次,那么为1的那些位统计的个数一定是2的倍数,抑或之后全变成0.一个数出现了一次,它为1的那些位上,1的个数必定是奇数,抑或之后一定还是1. 我之前知道出现两次这个题的解法,但是理解的不够深,以为抑或是关键,其实不是,出现了偶数次才是关键.理解了这点,推广到出现3次上,如果所有的出现了三次,那么为1的那些位1的个数一定是三的倍数,那如果有一个数出现了一次

让我们一起来实现一个完整的内存管理工具(线程,内存池,萃取)

//让我们开始一个完整的内存管理工具的实现吧. ///准备做一个完整的内存管理工具 //涉及线程,内存池,萃取,不仅仅是new跟delete的重载(或者说是函数重载),这是我的一个雏形,大家谁有什么好的指正谢谢提出,一起学习. #include <iostream> #include <string.h> #include <stdlib.h> #include <stdio.h> #include <list> #include <mal

windows平台上的一个内存池的实现

.h文件 /**********************说明************************* * 这是MPool内存池的实现,他具有如下特性: * 1. 池中的内存块是大小是相同的 * 2. 由宏定义_MP_NO_SERIALIZE决定是否需要多线程同步 * 3. 他利用windows的堆内存API进行内存分配 * 4. 他不能替换crt的malloc和free * 5. 他不是一个通用型的内存池 * 6. 适用于特定的应用环境(高频率的申请释放内存,如网络服务器),应用环境影

内存管理之内存池概述(转)

原文链接:http://www.xiaoyaochong.net/wordpress/index.php/2013/08/10/%E5%BC%95%E5%86%85%E5%AD%98%E7%AE%A1%E7%90%86%E4%B9%8B%E5%86%85%E5%AD%98%E6%B1%A0%E6%A6%82%E8%BF%B0/ 在我们编写代码的过程中,不可避免的要和内存打交道,在申请释放不太频繁的情况下,通常让系统进行内存管理即可.但是,直接使用系统调用malloc/free.new/delet

详谈内存管理技术(二)、内存池

嗯,这篇讲可用的多线程内存池. 零.上期彩蛋:不要重载全局new 或许,是一次很不愉快的经历,所以在会有这么一个"认识".反正,大概就是:即使你足够聪明,也不要自作聪明:在这就是不要重载全局new,无论你有着怎样的目的和智商.因为: class XXX{ public: XXX* createInstance(); }; 这是一个不对称的接口:只告诉了我们如何创建一个[堆]对象,但是释放呢??! 很无奈,只能假设其使用全局默认的delete来删除(除此之外,没有其他选择):这时,我为了