efficient c++,单线程内存池

基于 http://www.cnblogs.com/diegodu/p/4555018.html operator new的知识基础上 介绍这个章节的内容

对于一般直接 new 与delete 性能较差,可以自己管理写内存的申请与释放。其实一般的operator new 和operator delete 直接调用 malloc 和 free的。

版本0:

class Rational
{
public:
    Rational(int a=0, int b =1 ): n(a),d(b){}
private:
    int n;
    int d;
};

版本1:专用的内存管理器

#include <stddef.h> // for size_t
#include <iostream>

using namespace std;

class NextOnFreeList {
    public:
        NextOnFreeList *next;
};

class Rational {
    public:
        Rational (int a = 0, int b = 1 ) : n(a), d(b) {}
        inline void *operator new(size_t size);
        inline void operator delete(void *doomed, size_t size);

        static void newMemPool() { expandTheFreeList(); }
        static void deleteMemPool();

    private:
        static NextOnFreeList *freeList; // A free list of Rational objects.
        static void expandTheFreeList();
        enum { EXPANSION_SIZE = 32};

        int n; // Numerator
        int d; // Denominator
};

inline
void * Rational::operator new(size_t size)
{
    if (0 == freeList) {// If the list is empty, fill it up.
        expandTheFreeList();
    }

    NextOnFreeList *head = freeList;
    freeList = head->next;

    return head;
}

inline
void Rational::operator delete(void *doomed, size_t size)
{
    NextOnFreeList *head = static_cast <NextOnFreeList *> (doomed);
    head->next = freeList;
    freeList = head;
}

void Rational::expandTheFreeList()
{
    // We must allocate an object large enough to contain the next
    // pointer.
    size_t size = (sizeof(Rational) > sizeof(NextOnFreeList *)) ?
        sizeof(Rational) : sizeof(NextOnFreeList *);

//    NextOnFreeList *runner = static_cast <NextOnFreeList *>(new char[size]);
    NextOnFreeList *runner = (NextOnFreeList *)(new char[size]);

    freeList = runner;
    for (int i = 0; i < EXPANSION_SIZE; i++) {
        //runner->next = static_cast <NextOnFreeList *> (new char[size]);
        runner->next = (NextOnFreeList *)(new char[size]);
        runner = runner->next;
    }

    runner->next = 0;

    cout << "expand" << endl;
}

void Rational::deleteMemPool()
{
    NextOnFreeList *nextPtr;
    for (nextPtr = freeList; nextPtr != NULL; nextPtr = freeList) {
        freeList = freeList->next;
        delete [] nextPtr;
    }
}
//测试code

NextOnFreeList *Rational::freeList = 0;

int main()
{
    Rational *array[1000];

    Rational::newMemPool();

    // Start timing here

    for (int j = 0; j < 500; j++) {
        for (int i = 0; i < 1000; i++) {
            array[i] = new Rational(i);
        }
        for (int i = 0; i < 1000; i++) {
            delete array[i];
        }
    }

    // Stop timing here

    Rational::deleteMemPool();

    return 0;
}

这版本是通过重载 目标类 中的new 与delete 实现内存管理,只适用于目标类,但是速度是最快的。

实现方式是维护一个链表,类中静态声明链表头,链表维护一串空间,通过类型转换在  目标类 和 链表指针 之间转换。

如果内存不够(freelist=NULL)是一次申请较多内存进行维护。

链表的添加删除(对于函数释放空间与申请空间)是在链首操作。

书上47 行 52行通过 静态类型转换不成功,改为了 强制转换,在 g++ 中能够编译运行。

主要在主函数中调用静态函数 链表的申请与释放。

版本2:固定大小对象的内存池

考虑版本1,可以通过模板实现管理特定的对象。最主要的参数是类的大小。

实现是专门声明一个管理内存的内存池类,使用模板实现,提供alloc() free() 接口,给类申请与释放内存。

内存池类的实现是自身有一个MemoryPool<T>* next 指针用来指向维护的链表,内存的操作都在链首位置。

#include <stddef.h>
#include <iostream>

using namespace std;

template <class T>
class MemoryPool {
    public:
        MemoryPool (size_t size = EXPANSION_SIZE);
        ~MemoryPool ();

        // Allocate a T element from the free list.
        inline void* alloc (size_t size);

        // Return a T element to the free list.
        inline void free (void *someElement);
    private:
        // next element on the free list.
        MemoryPool<T> *next;

        // If the freeList is empty, expand it by this amount.
        enum { EXPANSION_SIZE = 32};

        // Add free elements to the free list
        void expandTheFreeList(int howMany = EXPANSION_SIZE);
};

template <class T>
MemoryPool <T> :: MemoryPool (size_t size)
{
    expandTheFreeList(size);
}

    template < class T >
MemoryPool < T > :: ~MemoryPool ()
{
    MemoryPool<T> *nextPtr = next;
    for (nextPtr = next; nextPtr != NULL; nextPtr = next) {
        next = next->next;
        cout << nextPtr << endl;
        //delete [] nextPtr;
        //delete  nextPtr;
        delete [](char*)nextPtr;  //不太明白为什么这样是对的,上面的方法不行。。                    //明白了,因为new的时候就是用char字节的方法申请的,delete的时候要对应。。
    }
}

template < class T >
    inline
void* MemoryPool < T > :: alloc (size_t)
{
    if (!next) {
        expandTheFreeList();
    }

    MemoryPool<T> *head = next;
    next = head->next;

    return head;
}

template < class T >
    inline
void MemoryPool < T > :: free (void *doomed)
{
    MemoryPool<T> *head = static_cast <MemoryPool<T> *> (doomed);

    head->next = next;
    next = head;
}

    template < class T >
void MemoryPool < T > :: expandTheFreeList(int howMany)
{
    // We must allocate an object large enough to contain the
    // next pointer.
    size_t size = (sizeof(T) > sizeof(MemoryPool<T> *)) ?
        sizeof(T) : sizeof(MemoryPool<T> *);

    //MemoryPool<T> *runner = static_cast <MemoryPool<T> *>(new char [size]);
    MemoryPool<T> *runner = (MemoryPool<T> *)(new char [size]);

    next = runner;
    for (int i = 0; i < howMany ; i++) {
        //runner->next = static_cast <MemoryPool<T> *> new char [size];
        runner->next = (MemoryPool<T> *)( new char [size]);
        runner = runner->next;
    }
    runner->next = NULL;
}

class Rational {
    public:
        Rational (int a = 0, int b = 1 ) : n(a), d(b) {}

        void *operator new(size_t size) { return memPool->alloc(size); }
        void operator delete(void *doomed,size_t size)
        { memPool->free(doomed); }

        static void newMemPool() { memPool = new MemoryPool <Rational>; }
        static void deleteMemPool() { delete memPool; }
    private:
        int n; // Numerator
        int d; // Denominator

        static MemoryPool <Rational> *memPool;
};

MemoryPool <Rational> *Rational::memPool = 0;

int main()
{
    Rational *array[1000];

    Rational::newMemPool();

    // Start timing here

    for (int j = 0; j < 500; j++) {
        for (int i = 0; i < 1000; i++) {
            array[i] = new Rational(i);
        }
        for (int i = 0; i < 1000; i++) {
            delete array[i];
        }
    }

    // Stop timing here

    Rational::deleteMemPool();

}
时间: 2024-10-19 02:05:15

efficient c++,单线程内存池的相关文章

内存池技术介绍(图文并茂,非常清楚)

看到一篇关于内存池技术的介绍文章,受益匪浅,转贴至此. 原贴地址:http://www.ibm.com/developerworks/cn/linux/l-cn-ppp/index6.html 6.1 自定义内存池性能优化的原理 如前所述,读者已经了解到"堆"和"栈"的区别.而在编程实践中,不可避免地要大量用到堆上的内存.例如在程序中维护一个链表的数据结构时,每次新增或者删除一个链表的节点,都需要从内存堆上分配或者释放一定的内存:在维护一个动态数组时,如果动态数组的

内存池技术的原理与实现

6.1 自定义内存池性能优化的原理 如前所述,读者已经了解到"堆"和"栈"的区别.而在编程实践中,不可避免地要大量用到堆上的内存.例如在程序中维护一个链表的数据结构时,每次新增或者删除一个链表的节点,都需要从内存堆上分配或者释放一定的内存:在维护一个动态数组时,如果动态数组的大小不能满足程序需要时,也要在内存堆上分配新的内存空间. 6.1.1 默认内存管理函数的不足 利用默认的内存管理函数new/delete或malloc/free在堆上分配和释放内存会有一些额外的

自定义内存池(C++需要掌握)

程序通过系统的内存分配一次性申请适当大小的内存作为一个内存池,之后应用程序自己对内存的分配和释放则可以通过这个内存池来完成.只有当内存池需要动态扩张时,才需要系统再调用内存分配函数,其它时间对内存的一切掌握都在应用程序的掌握之中. 从线程安全角度,内存池可以分为单线程内存池和多线程池 单线程内存池:单线程内存池在整个生命周期只被一个线程使用,因而不需要考虑互斥问题 多线程内存池:多线程内存池可能被多个线程共享,因此则需要在每次分配和释放内存时加锁. 一般而言,单线程内存池性能更好,而多线程内存池

分配固定大小对象的内存池

//下面的代码思想取自efficient c++ 1 ////////////////////////////////////////////////////////////////////////// 2 //可分为:1.内存池本身的创建和删除 3 // 2.内存池中空闲内存的维护 4 //两个部分区分开,逻辑就清晰了. 5 //by wangpei 2015.1.4 6 /////////////////////////////////////////////////////////////

c++内存池实现

利用C/C++开发大型应用程序中,内存的管理与分配是一个需要认真考虑的部分.本文描述了内存池设计原理并给出内存池的实现代码,代码支持Windows和Linux,多线程安全.内存池设计过程中需要考虑好内存的分配与释放问题,其实也就是空间和时间的矛盾.有的内存池设计得很巧妙,内存分配与需求相当,但是会浪费过多的时间去查找分配与释放,这就得不偿失:实际使用中,我们更多的是关心内存分配的速度,而不是内存的使用效率.基于此,本文按照如下思想设计实现内存池.主要包含三个结构:StiaticMemory, M

C++实现内存池

多进程编程多用在并发服务器的编写上,当收到一个请求时,服务器新建一个进程处理请求,同时继续监听.为了提高响应速度,服务器采用进程池的方法,在初始化阶段创建一个进程池,池中有许多预创建的进程,当请求到达时,只需从池中分配出来一个进程即可:当进程不够用时,进程池将再次创建一批进程.类似的方法可以用在内存分配上. C++中,创建一个复杂的对象需要几十条指令,包括函数调用的代价(寄存器值得保存和恢复),以及构造或复制构造函数体的执行代价,甚至动态分配内存的代价.尤其是,在不重载new和delete运算符

内存池、进程池、线程池

首先介绍一个概念"池化技术 ".池化技术 一言以蔽之就是:提前保存大量的资源,以备不时之需以及重复使用. 池化技术应用广泛,如内存池,线程池,连接池等等.内存池相关的内容,建议看看Apache.Nginx等开源web服务器的内存池实现. 起因:由于在实际应用当中,分配内存.创建进程.线程都会设计到一些系统调用,系统调用需要导致程序从用户态切换到内核态,是非常耗时的操作.           因此,当程序中需要频繁的进行内存申请释放,进程.线程创建销毁等操作时,通常会使用内存池.进程池.

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

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

InnoDB 存储引擎的线程与内存池

InnoDB 存储引擎的线程与内存池 InnoDB体系结构如下: 后台线程: 1.后台线程的主要作用是负责刷新内存池中的数据,保证缓冲池中的内存缓存的是最近的数据: 2.另外,将以修改的数据文件刷新到磁盘文件: 3.同时,保证在数据库发生异常的情况下,InnoDB能恢复到正常运行状态. 内存池:InnoDB有多个内存块,这些内存块组成了一个大的内存池.这些内存块包括有:缓冲池(innodb_buffer_pool)和日志缓冲(log_buffer)以及额外内存池(innodb_addtional