简单的内存分配器

采用自定义的operator运算符实现自己的内存分配策略,在某些时候可以提高程序的效率。

 

C++中的new运算符,具体工作流程如下:

1.调用operator new申请原始内存

2.调用place new表达式,执行类的构造函数

3.返回内存地址

而delete操作符的工作是:

1.调用对象的析构函数

2.调用operator delete释放内存

例如:

#include <iostream>
using namespace std;

class Test
{
public:
    Test() { cout << "Test" << endl; }
    ~Test() { cout << "~Test" << endl; }
};

int main(int argc, char const *argv[])
{

    //这里的pt指向的是原始内存
    Test *pt = static_cast<Test*>(operator new[] (5 * sizeof(Test)));

    for(int ix = 0; ix != 5; ++ix)
    {
        new (pt+ix)Test(); //调用定位new运算式 执行构造函数
    }

    for(int ix = 0; ix != 5; ++ix)
    {
        pt[ix].~Test(); //调用析构函数,但是并未释放内存
    }
    operator delete[] (pt); //释放内存

}

 

这里提供一个简单的内存分配器基类,凡是继承该类的class均具有自定义的operator new 和 operator delete

此示例来自《C++Primer》第四版

大概思想是用static变量维持一个链表,管理空闲的内存块。

#ifndef CACHED_OBJECT_HPP
#define CACHED_OBJECT_HPP

#include <memory>
#include <stdexcept>
#include <iostream> //debug

template <typename T>
class CachedObject
{
public:
    void *operator new(std::size_t);
    void operator delete(void *, std::size_t);
    virtual ~CachedObject() { }
protected:
    T *next_;
private:
    static void addToFreeList(T*);  //将内存块加入链表
    static std::allocator<T> alloc_;//内存分配器
    static T *freeStore_;           //空闲内存的链表
    static const std::size_t chunk_;//一次分配的块数
};

template <typename T> std::allocator<T> CachedObject<T>::alloc_;
template <typename T> T *CachedObject<T>::freeStore_ = NULL;
template <typename T> const std::size_t CachedObject<T>::chunk_ = 24;

template <typename T>
void *CachedObject<T>::operator new(std::size_t sz)
{
    if(sz != sizeof(T))
        throw std::runtime_error("CachedObject: wrong size object in operator new");

    std::cout << "operator new " << std::endl; //DEBUG

    //没有空闲内存
    if(freeStore_ == NULL)
    {
        T *array = alloc_.allocate(chunk_);
        for(std::size_t ix = 0; ix != chunk_; ++ix)
        {
            addToFreeList(&array[ix]);
        }
    }

    //取出一块内存,从链表取出第一个元素
    T *p = freeStore_;
    freeStore_ = freeStore_->CachedObject<T>::next_;
    return p;
}

template <typename T>
void CachedObject<T>::operator delete(void *p, std::size_t)
{
    std::cout << "operator delete " << std::endl; //DEBUG

    if(p != NULL)
        addToFreeList(static_cast<T*>(p));
}

template <typename T>
void CachedObject<T>::addToFreeList(T *p)
{
    //使用头插法
    p->CachedObject<T>::next_ = freeStore_;
    freeStore_ = p;
}

#endif /* CACHED_OBJECT_HPP */

每次执行new时,调用我们自定义的operator new去空闲链表中取出一块内存,如果链表为空,则执行真正的申请内存操作。

每次delete时,把内存归还给链表。

这样减少了每次new都去申请内存的开销。

测试代码如下:

#include "CachedObject.hpp"
#include <iostream>
using namespace std;

//使用继承的策略去使用这个内存分配器
class Test : public CachedObject<Test>
{

};

int main(int argc, char const *argv[])
{

    //调用自定义的new分配内存
    Test *pt = new Test;
    delete pt;

    //调用默认的new和delete
    pt = ::new Test;
    ::delete pt;

    //不会调用自定义的new和delete
    pt = new Test[10];
    delete[] pt; 

}
时间: 2024-10-11 21:23:28

简单的内存分配器的相关文章

一个简单的内存分配器-《深入理解计算机操作系统》

我相信很多人都知道<深入理解计算机操作系统>这本书,并且很多人都会对它研读.实际本人刚开始看的时候,只是加深了对操作系统的理解,别的到是没有感觉的到, 但是在看到公司的软件框架里面对于内存堆的管理,才发现和书上讲的异曲同工.于是乎,自己对利用隐式的空闲链表实现分配器做了总结,并且和自己想到的架构做了对比分析. 我们知道一个实际的分配器,不仅要考虑好吞吐率和内存利用率之间的平衡,还要考虑: ①空闲块组织:我们如何记录空闲块(一般刚开始会把一整段堆当做空闲块,然后再分割) ②放置:我们如何选择一个

内存分配器 (Memory Allocator)

对于大多数开发者而言,系统的内存分配就是一个黑盒子,就是几个API的调用.有你就给我,没有我就想别的办法.来UC前,我就是这样认为的.实际深入进去时,才发现这个领域里也是百家争鸣,非常热闹.有操作系统层面的内存分配器(Memory Allocator),有应用程序层面的,有为实时系统设计的,有为服务程序设计的.但他们的目的确认一样的,平衡内存分配的性能和提高内存使用的效率. 从浏览器开发的角度看,手机内存的增长速度相对于网页内容的增长仍然只是温暖水平,像Android这样的用内存大户更要算计着用

内核的bootmem内存分配器【转】

转自:http://blog.csdn.net/zmxiangde_88/article/details/8041040 版权声明:本文为博主原创文章,未经博主允许不得转载. 在内核启动期间,伙伴系统内存管理器还没有建立之前,内核此时也要分配内存以及创建一些用于建立内存管理等机制的数据结构,此时内存分配和管理就是由bootmem内存分配器来完成的. bootmem的建立要求就是简单,越简单越好,因为一旦伙伴系统建立之后,就不需要bootmem了,因此对性能和通用性等要服从一切从简的原则.在了解这

[转]Linux内核最新的连续内存分配器(CMA)——避免预留大块内存

http://blog.csdn.net/21cnbao/article/details/7309757 在我们使用ARM等嵌入式Linux系统的时候,一个头疼的问题是GPU,Camera,HDMI等都需要预留大量连续内存,这部分内存平时不用, 但是一般的做法又必须先预留着.目前,Marek Szyprowski和Michal Nazarewicz实现了一套全新的Contiguous Memory Allocator.通过这套机制,我们可以做到不预留内存,这些内存平时是可用的,只有当需要的时候才

Nah Lock: 一个无锁的内存分配器

概述 我实现了两个完全无锁的内存分配器:_nalloc 和 nalloc.  我用benchmark工具对它们进行了一组综合性测试,并比较了它们的指标值. 与libc(glibc malloc)相比,第一个分配器测试结果很差,但是我从中学到了很多东西,然后我实现了第二个无锁分配器,随着核数增加至30,测试结果线性提高.核数增加至60,测试结果次线性提高,但是仅比tcmalloc好一点. 想要安装,输入命令: git clone ~apodolsk/repo/nalloc,阅读 README文档.

Netty源码分析第5章(ByteBuf)----&gt;第3节: 内存分配器

Netty源码分析第五章: ByteBuf 第三节: 内存分配器 内存分配器, 顾明思议就是分配内存的工具, 在netty中, 内存分配器的顶级抽象是接口ByteBufAllocator, 里面定义了有关内存分配的相关api 抽象类AbstractByteBufAllocator实现了ByteBufAllocator接口, 并且实现了其大部分功能 和AbstractByteBuf一样, AbstractByteBufAllocator也实现了缓冲区分配的骨架逻辑, 剩余的交给其子类 以其中的分配

说下Redis采用不同内存分配器

参考文章: http://blog.sina.com.cn/s/blog_51df3eae01016peu.html 我们知道Redis并没有自己实现内存池,没有在标准的系统内存分配器上再加上自己的东西.所以系统内存分配器的性能及碎片率会对Redis造成一些性能上的影响. 在Redis的 zmalloc.c 源码中,我们可以看到如下代码: 49 #if defined(USE_TCMALLOC) 50 #define malloc(size) tc_malloc(size) 51 #define

[转]STL的内存分配器

题记:内存管理一直是C/C++程序的红灯区.关于内存管理的话题,大致有两类侧重点,一类是内存的正确使用,例如C++中new和delete应该成对出现,用RAII技巧管理内存资源,auto_ptr等方面,很多C/C++书籍中都使用技巧的介绍.另一类是内存管理的实现,如linux内核的slab分配器,STL中的allocator实现,以及一些特定于某种对象的内存管理等.最近阅读了一些内存管理实现方面的资料和源码,整理了一下,汇编成一个系列介绍一些常用的内存管理策略. 1. STL容器简介 STL提供

简单实现内存池

#include "common.h" #include "pool.h" #include <assert.h> static inline void *objmem_to_obj(void *objmem) { return objmem + sizeof(pool_obj_head_t); } static inline void *obj_to_objmem(void *obj) { return obj - sizeof(pool_obj_he