自定义堆分配器 - 分配的对象必须指向分配器?

时间:2017-05-27 07:39:40

标签: c++ memory-management allocator

在具有多个自定义堆分配器实例的环境中,
以下陈述是否正确? : -

  1. 每个分配的指针都应该封装在一个类型(例如Ptr)中 那个缓存指针分配给我(Allo*)的指针,例如

    class Ptr={     
        Allo* alloPtr;  //<-- to keep track
        public: void delete(){ 
            //call back to something like "a.deallocate()"
        }
    }
    Allo a;   //a custom allocator
    Ptr<X> x=a.allocate<X>();
    x.delete();  
    

    我认为我需要这样做才能让delete()更容易。

  2. 如果分配器更复杂,例如内部保留了很多块: -

    enter image description here

    Ptr应该跟踪它所在的块,或者
    在分配的内容之前必须有一些微小的标志: -

    enter image description here

    否则,我必须迭代每个块以找到地址 - &gt;表现不佳。

  3. 对不起,如果这太新手了,我对自定义分配器很新 这不是作业 - 我正在努力改进我的游戏库。

    我读过: -

1 个答案:

答案 0 :(得分:1)

有些实现将元数据保存在正在使用的对象附近,但这些系统受到安全性的影响。

如果您可以控制缓冲区溢出或缓冲区欠载,则可以修补分配器元数据的内存,从而导致代码执行而不是分配。

我见过一种实现,它使用完全独立的内存区域来存储数据和元数据。这可以确保可以识别超出和欠载,错误释放。

该系统的缺点是从指针搜索元数据。

这意味着某种形式的容器需要键入内存,并且受到与大多数容器实现相关联的O(ln n)形式的性能的影响,因此在管理方面的性能低于数据的性能。本地

更新

就地元数据

+----------+               +-----------+           +--------------+
| pointer  |               | vtable    | ------->  | int free()   |
| to chunk | ------------->|meta data  |           S void*alloc() S
+----------+               +-----------+
|memory    |
|          |
+----------+

指向块的指针发生在返回的内存之前,之后(或之后)。 如果在指针数组中使用了内存,则内存[-1]是有效内存,但指向元数据。如果从代码外部,我可以说服它在那里写一个值,我已经控制了程序,因为它将寻找我可以控制的vtable

更新2

让我再试一次

  

每个分配的指针都应该封装在一个类型中(例如Ptr)   那个分配给我的人的缓存指针(Allo *),例如

所以特别不一定每个项目都有自己的元数据。

为了跟踪分配,了解使用哪种方案非常重要。在现代编程中,通常对小项目(<10字节)的分配处理不同于大(> 500字节)的项目。可以从数组中的插槽分配小项目,只保留块的元数据。

较大的尺寸不需要相同的膨胀量,因为开销的相对成本会下降。

我希望将小内存块一起批处理,较大的项目具有单独的元数据。

  

Ptr应该跟踪它所驻留的块,或者   在分配的内容之前必须有一些微小的标志: -

具体来说,需要找到一种方法来找到用于分配的内存分配方案,这可以通过存储带分配的元数据,或者通过分配地址键入一些外部方案来找到记忆(例如)

std::map<void*, MetaData> mMetadataChunk;

注意使用std :: map分配的危险,每个跟踪项目有2个内存分配。

还存在简单的分配方案,将(线程安全的)链接列表添加到特定类,允许为给定对象轻松地重用内存

 class FrequentAllocateDestroy {
      ...
      static SomeListType mSpare;
      void* operator new  ( std::size_t count ) {
          // lock 
          if (mSpare.empty ) {
              return ::new( count );
          } else {
              void * mem = mSpare.top();
              mSpare.pop();
              return mem;
          }
      }
      void operator delete( void * mem){
           // lock
           mSpare.push( mem );
      }
 }