-1

通常の新しいオペレーターに代わる小さなメカニズムを作成しました。基本的に、メモリのプール (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 に答える