简体   繁体   English

对C ++堆分配器和STL进行碎片整理

[英]Defragmenting C++ Heap Allocator & STL

I'm looking to write a self defragmenting memory manager whereby a simple incrementing heap allocator is used in combination with a simple compacting defragmenter. 我正在寻找一种自我碎片整理内存管理器,其中将简单的增量堆分配器与简单的压缩碎片整理程序结合使用。

The rough scheme would be to allocate blocks starting at the lowest memory address going upwards and keeping book-keeping information starting at the highest memory address working downwards. 粗略的方案是分配从最低内存地址开始向上的块,并保持从最高内存地址开始的簿记信息向下工作。

The memory manager would pass back smart pointers - boost's intrusive_ptr's seems the most obvious to the book-keeping structs that would then themselves point to the actual memory block thus giving a level of indirection so that the blocks can be easily moved around. 内存管理器会传回智能指针-boost的intrusive_ptr似乎对簿记结构最为明显,然后它们自身会指向实际的内存块,从而提供一定程度的间接性,以便可以轻松地移动这些块。

The defragmenter would compact down the heap starting at 'generation' bookmarks to speed up the process and only defragmenting a fixed amount of memory at a time. 碎片整理程序将从“生成”书签开始压缩堆,以加快处理速度,并且一次仅整理固定数量的内存。 Raw pointers to the blocks themselves would be valid until the next defrag pass and so could be passed around freely until such a time improving performance. 指向块本身的原始指针将在下一次碎片整理通过之前一直有效,因此可以自由传递,直到提高性能为止。

The specific application for this is console game programming and so at the beginning or end of each frame a defrag pass could be done relatively safely. 特定的应用是控制台游戏编程,因此可以在每帧的开始或结束时相对安全地进行碎片整理。

So my question is has anybody used this kind of allocation scheme in combination with STL would it just completely blow STL apart as I suspect. 因此,我的问题是,有人怀疑将这种分配方案与STL结合使用是否会使STL完全分开呢? I can see std::list< intrusive_ptr > working at the intrusive_ptr level but what about the allocation of the stl list nodes themselves is there anyway to override the next/prev pointers to be intrusive_ptr's themselves or am I just going to have to have a standard heap allocator along side this more dynamic one. 我可以看到std :: list <intrusive_ptr>在intrusive_ptr级别上工作,但是stl列表节点本身的分配又可以覆盖next / prev指针本身是intrusive_ptr本身,还是我只需要一个标准堆分配器旁边是这种更动态的分配器。

If you're going to be moving objects around in memory then you can't do this fully generically. 如果要在内存中移动对象,则不能完全按照常规方式进行。 You will only be able to do this with objects that know that they might be moved. 您只能使用知道它们可能已移动的对象来执行此操作。 You also will need a locking mechanism. 您还需要一个锁定机制。 When a function is being called on an object, then it can't be moved. 在对象上调用函数时,将无法移动它。

The reason is that the whole C++ model relies on objects sitting at fixed points in memory, so if a thread was calling a method on an object, this thread was paused and the object moved, disaster would strike when the thread resumed. 原因是整个C ++模型都依赖于位于内存中固定点的对象,因此,如果线程在对象上调用方法,则该线程将暂停并且对象移动,恢复线程时将发生灾难。

Any object which held a raw memory pointer to another object that might be moved (including a sub-object of itself) would not work. 任何将原始内存指针保存到可能移动的其他对象的对象(包括其自身的子对象)将无法工作。

Such a memory management scheme may work but you have to be very careful. 这样的内存管理方案可能会起作用,但是您必须非常小心。 You need to be strict about implementing handles, and the handle->pointer locking semantics. 您需要严格地实现句柄,以及handle-> pointer锁定语义。

For STL containers, you can customize the allocator, but it still needs to return fixed raw memory pointers. 对于STL容器,您可以自定义分配器,但仍然需要返回固定的原始内存指针。 You can't return an address that might move. 您无法返回可能移动的地址。 For this reason, if you're using STL containers, they must be containers of handles, and the nodes themselves will be ordinary dynamically allocated memory. 因此,如果您使用的是STL容器,则它们必须是句柄的容器,并且节点本身将是普通的动态分配的内存。 You may find that you too much in overhead in the handle indirection and still have problems in the fragmentation of the handle collections than you gain by using STL. 您可能会发现您在句柄间接中的开销过多,而句柄集合的碎片化仍然比使用STL获得的问题多。

Using containers that understand your handles directly might be the only way forward, and even then there may still be a lot of overhead compared to a C++ application that uses traditional objects fixed in memory. 使用直接理解您的句柄的容器可能是前进的唯一方法,即使那样,与使用固定在内存中的传统对象的C ++应用程序相比,仍然会有很多开销。

STL containers are implemented using naked pointers. STL容器使用裸指针实现。

You can specify a custom allocator when you instantiate them (so they they initialize their pointers using your allocator), but (because the allocated values are stored in naked pointers) you don't know where those pointers are, and therefore you can't change them later. 您可以在实例化自定义分配器时指定它们(以便它们使用分配器初始化它们的指针),但是(由于分配的值存储在裸指针中),您不知道这些指针在哪里,因此您无法以后再换。

Instead, you might consider implementing a subset of the STL yourself: your versions of the STL containers could then be implemented with managed pointers. 相反,您可以考虑自己实现STL的子集:然后可以使用托管指针来实现STL容器的版本。

An alternative technique which is fairly well known is the buddy system . 众所周知的另一种技术是伙伴系统 You should take a look at that for additional inspiration. 您应该查看一下以获取其他启发。

If this is for console game programming it's a lot easier to forbid un-scoped dynamic memory allocations at runtime. 如果这是用于控制台游戏编程,则在运行时禁止未限制范围的动态内存分配要容易得多。 And at startup time, but that's a bit difficult to achieve. 而且在启动时,这很难实现。

My take on this, is that if have to be afraid of fragmentation, that means you are juggling around with data pieces which are a huge fraction of your memory, and by this virtue alone, you cannot have many of them. 我对此的看法是,如果必须担心碎片化,那就意味着您正忙于处理占内存很大一部分的数据,而仅凭这一点,就不能拥有很多数据。 Do you already know what these will be? 您已经知道这些将是什么吗? Maybe it would be better to step down a level and make more specific decisions, thus impeding less on the other code and the general performance of your application? 也许最好降低某个级别并做出更具体的决定,从而减少对其他代码和应用程​​序总体性能的影响?

A list is an exceptionally bad example to put into a defragmenting memory manager, because it's a bunch of tiny pieces, as are most other STL data structures. 列表是放入碎片整理的内存管理器中的一个非常糟糕的例子,因为它和其他大多数STL数据结构一样都是一小块。 If you do this, it will have all kinds of obvious bad implications - including the performance of your defragmenter going down, also the indirection cost etc. The only structures where it makes sense IMO are contigious ones - array, deque, main chunk of hashtable, those things, and only beyond a certain size, and only after they are not gonna be resized any longer. 如果这样做,它将带来各种明显的不良影响-包括碎片整理程序的性能下降,间接成本等。使IMO有意义的唯一结构是连续的结构-数组,双端队列,哈希表的主要块,这些东西,并且只能超出一定的大小,并且只有在不再调整大小之后才可以。 These kind of things call, again, for specific solutions, instead of generic ones. 这些事情再次要求特定的解决方案,而不是通用的解决方案。

Comment back on how it all turns out. 回顾一下结果。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM