简体   繁体   English

将C ++对象(尤其是stl容器)移动到特定的内存位置

[英]Moving C++ objects, especially stl containers, to a specific memory location

I am working with a memory manager that, on occasion, wants to defragment memory. 我正在与一个内存管理器合作,有时候想要对内存进行碎片整理。 Basically, I will go through a list of objects allocated by the memory manager and relocate them: 基本上,我将查看内存管理器分配的对象列表并重新定位它们:

class A {
  SomeClass* data; // This member is allocated by the special manager
};

for(... each instance of A ...) 
    a.data = memory_manager.relocate(a.data);

memory_manager.relocate() will memcpy() the contents of data to a new location, and return the pointer. memory_manager.relocate()memcpy()将数据的内容转移到新位置,并返回指针。

Although it's generally not idiomatic to memcpy() C++ classes, it seems to be a useful solution in this case, considering that I control the implementation of the (few) classes that will be used with the memory manager. 尽管对于memcpy() C ++类来说它通常不是惯用的,但考虑到我控制将与内存管理器一起使用的(少数)类的实现,它在这种情况下似乎是一个有用的解决方案。

The problem is that one of those classes uses std::map , which is an opaque class as far as I am concerned. 问题是其中一个类使用std::map ,就我而言,这是一个不透明的类。 I certainly don't imagine I can memcpy() it. 我当然不认为我可以memcpy()它。 I may not be able to use std::map in any case. 在任何情况下我都可能无法使用std :: map。 For all I know it could allocate several pieces of memory. 据我所知,它可以分配几块内存。

The best workaround I can think of is simple enough. 我能想到的最好的解决方法很简单。 Due to the fact that the fragmented memory manager will put new allocations at more beneficial locations, all I need to do is allocate it anew and then delete the old: 由于碎片化的内存管理器将新的分配放在更有利的位置,我需要做的就是重新分配它然后删除旧的:

for(... each instance of A ...) {
    stl::map<something>* tmp = a.the_map;
    a.the_map = new stl::map<something>(tmp);
    delete tmp;
}



In any case, this lead me to wonder: 无论如何,这让我想知道:

Does C++ have semantics or idioms to move/copy an object into a specific memory location? C ++是否具有将对象移动/复制到特定内存位置的语义或习语?

Is it possible to move the contents of an stl container to a specific memory location? 是否可以将stl容器的内容移动到特定的内存位置?


Edit: Although I didn't point it out, I would obviously pass an allocator parameter to std::map. 编辑:虽然我没有指出,我显然会将一个allocator参数传递给std :: map。 Based on the informative answers I got, I realize the workaround I posted in my initial question would probably be the only way to reduce fragmentation. 基于我得到的信息性答案,我意识到我在初始问题中发布的解决方法可能是减少碎片的唯一方法。 By using the map's copy constructor (and the allocator template parameter), all memory used by the map would be properly re-allocated. 通过使用map的复制构造函数(和allocator模板参数),可以正确地重新分配映射使用的所有内存。

As a comment pointed out, this is mostly a theoretical problem. 正如评论所指出的,这主要是一个理论问题。 Memory fragmentation is rarely something to worry about. 内存碎片很少需要担心。

Everytime you insert a new key,value pair the map will allocate a node to store it. 每次插入新键,值对时,映射都会分配一个节点来存储它。 The details of how this allocation takes place are determined by the allocator that the map uses. 这种分配如何发生的细节由地图使用的分配器决定。

By default when you create a map as in std::map<K,V> the default allocator is used, which creates nodes on the heap (ie, with new / delete ). 默认情况下,在std::map<K,V>创建映射时std::map<K,V>将使用默认分配器,它在堆上创建节点(即使用new / delete )。

You don't want that, so you'll have to create a custom allocator class that creates nodes as dictated by your memory manager. 您不希望如此,因此您必须创建一个自定义分配器类,该类根据内存管理器的要求创建节点。

Creating an allocator class is not trivial. 创建一个allocator类并不简单。 This code shows how it can be done, you'll have to adapt it to your own needs. 此代码显示了如何完成,您必须根据自己的需要进行调整。

Once you have your allocator class (let's say you call it MemManagerAllocator ) you'll have to define your map as std::map<K, V, MemManagerAllocator> and then use it like you would use a regular map. 一旦你有了你的分配器类(假设你称之为MemManagerAllocator ),你必须将你的地图定义为std::map<K, V, MemManagerAllocator> ,然后像使用常规地图一样使用它。

Personally, I would need to have a really bad problem of memory fragmentation to go into all that trouble. 就个人而言,我需要有一个非常糟糕的内存碎片问题才能解决所有麻烦。

The contents of a C++ object will be scattered around the heap. C ++对象的内容将分散在堆中。 A STL object for example a container or string etc might store its meta-data on your stack (if you don't put it in dynamic memory) ... however the contents are scattered arround the heap. STL对象(例如容器或字符串等)可能会将其元数据存储在堆栈中(如果不将其放在动态内存中)......但是内容会分散在堆中。

It will be a hard task to keep track of all the elements of an object, and all the references to these elements. 跟踪对象的所有元素以及对这些元素的所有引用将是一项艰巨的任务。 The language has to provide some form of "hooks" or events to enable tracking the relationships between chunks of memories. 语言必须提供某种形式的“钩子”或事件,以便跟踪记忆块之间的关系。

So no, you can't just memcpy a arbitrary STL object. 所以不,你不能只记忆一个任意的STL对象。

Afaik overriding new is not a panacea, it is a "process global" concept so trying to localize the news to a thread-object-allocation pair is not possible. Afaik压倒新的不是灵丹妙药,它是一个“进程全局”概念,因此尝试将新闻本地化为线程 - 对象 - 分配对是不可能的。 And this localization would enable you to group the memory together. 这种本地化将使您能够将内存组合在一起。

You could write your own containers that used a custom memory allocator explicitly (explicit because your provide the necessary object identity information), and there are some custom allocators out there. 您可以编写自己的容器,显式地使用自定义内存分配器(显式,因为您提供了必要的对象标识信息),并且有一些自定义分配器。

You could use placement new? 您可以使用新的展示位置?

void* adress = new void[size_of(*old_map_ptr)]; // or wherever you want it in your memory
map<type> new_map* = new (adress) map<type>(*old_map_ptr);
delete old_map_ptr;

不,C ++本身只管理内存,但你可以通过实现std :: map :: allocator来帮助stl实现它,它会一直这样做,所以你不需要memcpy它。

You did not mention which platform you are coding for or if that is allowed to matter. 您没有提到您正在编码的平台,或者是否允许这样做。 But in Linux and the GCC, the C++ default allocator is implemented with malloc . 但是在Linux和GCC中,C ++默认分配器是用malloc实现的。

malloc can be overridden and replaced with your own internal allocator. malloc可以被覆盖并替换为您自己的内部分配器。

I would implement this malloc as follows: 我会按如下方式实现这个malloc

in the general case, just defer to original malloc . 在一般情况下,只需遵循原始的malloc Whenever you want to, you can change the behavior of the malloc function to return pointers to this special memory area you have prepared. 无论何时,您都可以更改malloc函数的行为,以返回指向您准备的特殊内存区域的指针。

So, before creating this particular std::map you would give your malloc a hint. 因此,在创建这个特定的std::map你会给malloc一个提示。 (Through a global variable or some other means of communication.) (通过全局变量或其他一些通信手段。)

Update: alemjerus suggested implementing std::map::allocator which is a much cleaner way on the same theme, also platform agnostic. 更新:alemjerus建议实现std::map::allocator ,这是一个清晰的方式在同一主题,也是平台无关。

You can use placement new to define where the base std::map object lives. 您可以使用placement new来定义base std :: map对象所在的位置。 But the majority of the space will be allocated on the heap, by std::map. 但是大部分空间将通过std :: map在堆上分配。

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

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