构建内存管理器

news/2024/7/20 12:36:17 标签: 内存管理, c/c++, 数据库

简介: 代码的性能优化是一项非常重要的工作。经常可以看到,采用 C 或 C++ 编写的、功能正确的软件在执行时耗费大量的内存、时间、或者在最糟的情况下既耗内存又费时间。作为一名开发人员,可以使用 C/C++ 提供的功能强大的工具来改进处理时间,并且防止内存破坏,这些工具其中之一是控制如何在代码中分配或者释放内存。

忆一下 C/C++ 中内存管理的基础知识。执行时,malloc 和 new 将向操作系统内核请求内存,而 free 和 delete 则请求释放内存。这意味着,操作系统必须在每次提出内存请求时在用户空间代码和内核代码之间进行切换。反复调用 malloc 或者 new 的程序,最终将由于不断地进行上下文切换而导致运行缓慢。

设计目标

 

您的内存管理器应该满足下面的设计目标:

 

  • 速度
  • 健壮性
  • 用户使用便利性
  • 可移植性

 

 

速度

与编译器提供的分配器相比,内存管理器的速度必须更快一些。重复的分配和释放不应该降低代码的执行速度。如果可能的话,应该对内存管理器进行优化,以便处理代码中频繁出现的某些分配模式。

健壮性

在程序终止之前,内存管理器必须归还它向系统请求的所有内存。也就是说,不应该存在内存泄漏。它还应该能够处理错误的情况(例如,请求过大的内存),并且很好地解决这些问题。

用户使用便利性

在将内存管理器集成到他们的代码中时,用户应该只需要更改很少的代码。

可移植性

应该可以很容易地将内存管理器移植到其它的系统,并且不应该使用与平台相关的内存管理特性。

创建内存管理器的实用策略

在创建内存管理器时,下面的这些策略是很实用的:

  • 请求较大的内存块。
  • 对常见的请求大小进行优化。
  • 在容器中收集删除的内存。

请求较大的内存块

最常见的内存管理策略之一是,在程序启动期间请求一些较大的内存块,然后在代码执行期间反复地使用它们。可以从这些内存块划出部分内存,以满足各种数据结构的内存分配请求。这将极大地减少系统调用的次数,并提高执行性能。

对常见的请求大小进行优化

在任何程序中,某些特定的请求大小将比其它大小的请求更加常见。如果对您的内存管理器进行优化以便更好地处理这些请求,那么它将工作得更加出色。

在容器中收集删除的内存

 

应该将程序执行期间删除的内存收集到容器中。然后,应该使用这些容器来满足进一步的内存请求。如果某个请求失败,那么应该将内存访问委托给程序启动期间分配的某个较大的内存块。虽然内存管理最初用于加速程序的执行和防止内存泄漏,但这种技术可能会潜在地导致程序的较低内存空间占用,这是因为它可以重用删除的内存。这是编写您自己的内存分配器的另一个原因!

 

代码实现

 

#include <iostream>
#include <time.h>
#define POOLSIZE 32
//#define MY_MAMORYMANAGE //注释此行为关闭内存管理器,否则打开

using namespace std;

#ifdef MY_MAMORYMANAGE

class IMemoryManager 
{
public:
    virtual void* allocate(size_t) = 0;
    virtual void   free(void*) = 0;
};

class Complex 
{
public:
    Complex (double a, double b): r (a), c (b) {}
    inline void* operator new(size_t);
    inline void   operator delete(void*);private:
    double r; // Real Part
    double c; // Complex Part
}; 

class MemoryManager: public IMemoryManager 
{ 
public:
    MemoryManager () 
    { 
        freeStoreHead = 0;
        expandPoolSize ();
    }
    virtual ~MemoryManager () 
    {
        cleanUp ();
    }
    virtual void* allocate(size_t);
    virtual void   free(void*);
private:
    struct FreeStore
    {
        FreeStore *next;
    }; 
    void expandPoolSize ();
    void cleanUp ();
    FreeStore* freeStoreHead;
};

MemoryManager gMemoryManager; // Memory Manager, global variable


inline void* MemoryManager::allocate(size_t size)
{
    if (0 == freeStoreHead)
        expandPoolSize ();
    
    FreeStore* head = freeStoreHead;
    freeStoreHead = head->next;
    return head;
}

inline void MemoryManager::free(void* deleted)
{
    FreeStore* head = static_cast <FreeStore*> (deleted);
    head->next = freeStoreHead;
    freeStoreHead = head;
}

void MemoryManager::expandPoolSize ()
{
    size_t size = (sizeof(Complex) > sizeof(FreeStore*)) ?
        sizeof(Complex) : sizeof(FreeStore*);
    FreeStore* head = reinterpret_cast <FreeStore*> (new char[size]);
    freeStoreHead = head;
    
    for (int i = 0; i < POOLSIZE; i++) 
    {
        head->next = reinterpret_cast <FreeStore*> (new char [size]);
        head = head->next;
    }
    
    head->next = 0;
}

void MemoryManager::cleanUp()
{
    FreeStore* nextPtr = freeStoreHead;
    for (; nextPtr; nextPtr = freeStoreHead) 
    {
        freeStoreHead = freeStoreHead->next;
        delete [] nextPtr; // remember this was a char array
    }
} 


void* Complex::operator new (size_t size) 
{
    return gMemoryManager.allocate(size);
}

void Complex::operator delete (void* pointerToDelete)
{
    gMemoryManager.free(pointerToDelete);
} 

#else

class Complex 
{
public:
    Complex (double a, double b): r (a), c (b) {}
private:
    double r; // Real Part
    double c; // Complex Part
};

#endif // MY_MAMORYMANAGE



int main(int argc, char* argv[]) 
{
    Complex* array[1000];
    clock_t start_t,end_t;
    
    start_t = clock(); 
    for (int i = 0;i  <  5000; i++) 
    {
        for (int j = 0; j  <  1000; j++) 
        {
            array[j] = new Complex (i, j);
        }
        for (j = 0; j  <  1000; j++) 
        {
            delete array[j];
        }
    }
    end_t = clock();
    cout<<(end_t-start_t)/1000.0<<endl;
    return 0;
}

实验结果(windows下VC6.0):

未使用自构建的内存管理器,平均耗时:1.9秒+

使用后平均:0.4秒+

P.S.开源项目MYSQL中也是使用自己构建的内存管理器,以加快程序速度和保证程序健壮性。以上文字均来源于网络,这里只是重排而已。

 

 

转载于:https://www.cnblogs.com/legendmaner/archive/2012/11/04/2753373.html


http://www.niftyadmin.cn/n/1813557.html

相关文章

common controls 最新6.00_我和女神的荒岛余生全文免费阅读_我和女神的荒岛余生最新章节_顾小正的小说...

徒弟都是大魔头玄幻奇幻连载"初到玄幻&#xff0c;废柴模板&#xff0c;唯有收徒108个&#xff0c;授传108条大道传承才可逆天改命。 但夜北大寿耗尽&#xff0c;也没有盼到这一天。 就在他死后三百年。 所有徒弟&#xff0c;传承修成。 他逆天改命&#xff0c;重归玄幻。…

static在c语言与c++的区别

static在c语言与c的区别 1、C语言与C公有&#xff1a; &#xff08;1&#xff09;静态变量 ①静态变量只初始化一次&#xff0c;未初始化的静态变量会默认初始化为0。 ②静态全局变量只在本文件可见&#xff0c;外部文件无法访问。 ③静态局部变量只在定义的作用域内可见&#…

gridControl控件动态绑定列

DataTable dt Query.GetCustome(ref customColumnCount);//绑定列gridView.Columns.Add(new GridColumn() { Name "NoCHK", FieldName "NoCHK", Caption "选择", VisibleIndex 0});gridView.Columns.Add(new GridColumn() { Name "No&…

JS如何控制checkbox的全选反选

JS代码&#xff1a; 1 <script language"javascript" type"text/javascript">2 3 //转载请保留出处 http://www.dwww.cn 4 function unselectall() {5 if (document.getElementById("chkAll").checked) {6 …

用imspost制作catia后处理_资兴成都亚克力制作加工

资兴成都亚克力制作加工亚克力又叫PMMA或有机玻璃&#xff0c;源自英文acrylic()&#xff0c;化学名称为。它是一种开发较早的重要可塑性&#xff0c;具有较好的透明性、和&#xff0c;易染色、易加工、外观优美&#xff0c;在建筑业中有着广泛的应用。其产品通常可以分为浇注板…

C#后台数据处理常用方法

C#后台数据处理常用方法 1.后台脚本注册 StringBuilder sb new StringBuilder();sb.Append( "<script languagejavascript>" );sb.Append( "parent.location.href ../Logout.aspx" );sb.Append( "</script>");Cl…

java 设计模式学习笔记十六 chain of responsibility 职责链设计模式

chain of responsibility 职责链设计模式 是用一系列的classes处理一个请求&#xff0c;来一个请求&#xff0c;a先处理&#xff0c;如果没有处理&#xff0c;则b 处 理&#xff0c;如果没有处理&#xff0c;则由c处理&#xff0c;这样传递一个请求 示例代码如下&#xff1a; 方…

postgresql 连续5天发生_箭鱼电销机器人:连续拒绝一个AI电话机器人5次会发生什么?...

正常的电话销售&#xff0c;在面临客户连续5次的拒绝&#xff0c;也很难做到从容不迫的继续积极应对转化。那么如果同样的情形发生在机器人身上呢&#xff1f;我们知道&#xff0c;机器人是没有情绪的&#xff0c;但被连续拒绝5次&#xff0c;机器人会如何处理&#xff1f;是直…