-1

我制作了一个小机制来替换常规的 new 运算符。基本上,我们分配一个内存池(如 16mb),当调用 new 时,返回一个偏移量,该偏移量会增长直到没有更多空间,然后我们再创建一个池。只有当池中的所有元素都被释放时,池才会被删除。

我已经测试过这个类,它工作得很好,比原来的新类快 8-15 倍。但是有一个问题:我将它合并到我的另一个规模巨大的项目中,它正常工作,除了内存使用量增长非常快。基本上不会释放池,因为其中的某些项目根本没有被删除。此外,还有许多从 STL 容器对 new(0) 的调用,我不知道它应该如何响应。

这是代码:

namespace rt
{
      class pool
      {
            friend class alloc;
            private:
                    unsigned int _numRecords;
                    unsigned int _sizeLeft;
                    char*        _ptr;
                    char*        _data;


      };


      class alloc
      {
            public:
                   alloc();

                   alloc(int mb);

                   ~alloc();

                   void* allocate(unsigned int size);

                   void constructPool(unsigned int idx);

                   void destroyPool(unsigned int idx);

                   void deallocate(void* ptr);

            private:
                    const static unsigned int           _numPools = 256;
                    const static unsigned int           _poolSize = 15*1024*1024;
                    const static unsigned int           _poolReplaceBound = 1*1024*1024; // if 1mb or less left we can replace it
                    pool*                               _pools[_numPools];
                    unsigned int                        _curPoolIdx;


      };          

那是标题。这是实现:

namespace rt
{
          class pool
          {
                friend class alloc;
                private:
                        unsigned int _numRecords;
                        unsigned int _sizeLeft;
                        char*        _ptr;
                        char*        _data;

          };


      class alloc
      {
            public:
                   alloc();

                   alloc(int mb);

                   ~alloc();

                   void* allocate(unsigned int size);

                   void constructPool(unsigned int idx);

                   void destroyPool(unsigned int idx);

                   void deallocate(void* ptr);

            private:
                    const static unsigned int           _numPools = 256;
                    const static unsigned int           _poolSize = 15*1024*1024;
                    const static unsigned int           _poolReplaceBound = 1*1024*1024; // if 1mb or less left we can replace it
                    pool*                               _pools[_numPools];
                    unsigned int                        _curPoolIdx;


      };          

      extern alloc default_allocator;
}


#define RT_SAFE_MEM
namespace rt
{
      alloc default_allocator;


      alloc::alloc() 
      {
                     for(int i = 0; i < _numPools; i++) _pools[i] = NULL;
                     _curPoolIdx = 0;
                     constructPool(_curPoolIdx);
      }

      alloc::~alloc()
      {

      }

      void alloc::constructPool(unsigned int idx)
      {
                                    _pools[idx] = (pool*)malloc(sizeof(pool));
                                    _pools[idx]->_numRecords = 0;
                                    _pools[idx]->_sizeLeft = _poolSize;
                                    _pools[idx]->_data = (char*)calloc(_poolSize, 1);

                                    _pools[idx]->_ptr = _pools[idx]->_data; 
      }

      void alloc::destroyPool(unsigned int idx)
      {
           free(_pools[idx]->_data);
           free(_pools[idx]);
           _pools[idx] = NULL;
      }

      void* alloc::allocate(unsigned int size)
      {
            if(size == 0)
            {
                    return NULL;
            }
            #ifdef RT_SAFE_MEM

                                  if(size > _poolSize) 
                                  {
                                          MessageBox(NULL, "Allocation size exceeded maximum.", "Executor", MB_OK);
                                          return NULL;
                                  }
                                  if(*(_pools[_curPoolIdx]->_ptr) != 0)
                                  {
                                                                  //leak
                                                                  unsigned int leaksize = strlen(_pools[_curPoolIdx]->_ptr);
                                                                  char str[50];
                                                                  sprintf(str, "Memory corruption detected: wrote extra %u bytes. \nExporting to corrupt.txt", leaksize);
                                                                  FILE* fp = fopen("corrupt.txt", "w");
                                                                  fwrite(_pools[_curPoolIdx]->_ptr, 1, leaksize, fp);
                                                                  fclose(fp);
                                                                  MessageBox(NULL, str, "Executor", MB_OK);
                                                                  return NULL;
                                  }

            #endif

            if(_pools[_curPoolIdx]->_sizeLeft <= size)
            {
                                              //not enough size in this pool
                                              //make a new one
                                              _curPoolIdx++;
                                              //printf("expand");
                                              constructPool(_curPoolIdx);
                                              return allocate(size);

            }
            else
            {
                void* ans = (void*)_pools[_curPoolIdx]->_ptr;
                _pools[_curPoolIdx]->_ptr+=size;
                _pools[_curPoolIdx]->_sizeLeft-=size;
                _pools[_curPoolIdx]->_numRecords++;
                return ans;
            }
      }


      void alloc::deallocate(void* ptr)
      {
           for(int i = 0; i <= _curPoolIdx; i++)
           {
                   if(ptr >= _pools[i]->_data && ptr < _pools[i]->_ptr)
                   { 
                          //pool i contains this object
                          //printf("found %d\n", i); 
                          _pools[i]->_numRecords--;
                          if(_pools[i]->_numRecords == 0 && _pools[i]->_sizeLeft <= _poolReplaceBound)
                          {
                                                    //replace this pool
                                                    printf("replacing %d\n", i);
                                                    destroyPool(i);
                                                    if(_curPoolIdx == 0) constructPool(0);
                                                    else
                                                    {
                                                        for(int j = i; j < _numPools-1; j++)
                                                        {
                                                                _pools[j] = _pools[j+1];
                                                        } 
                                                        _curPoolIdx--;
                                                    }

                          }
                          return;
                   }
           }
           #ifdef RT_SAFE_MEM
                  char str[50];
                  sprintf(str,  "Attempted to deallocate foreign memory at 0x%.8X.", ptr);
                  MessageBox(NULL, str, "Executor", MB_OK);
           #endif
      }

}

如果有人发现错误或重大问题,请告诉我。谢谢!

4

1 回答 1

2

我建议您执行以下所有步骤:

  1. 编写一个测试程序来测试您的程序是否运行无错误或“有任何问题”
  2. 使用调试器来查找错误,而不是 SO 的受众 :-P
  3. 与其发布完整的代码列表,不如写下代码的作用——这将为您提供一个很好的参考点,同时也将为您的代码做什么(以及如何)提供有用的文档
于 2012-08-01T18:51:00.917 回答