繁体   English   中英

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

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

我正在与一个内存管理器合作,有时候想要对内存进行碎片整理。 基本上,我将查看内存管理器分配的对象列表并重新定位它们:

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()memcpy()将数据的内容转移到新位置,并返回指针。

尽管对于memcpy() C ++类来说它通常不是惯用的,但考虑到我控制将与内存管理器一起使用的(少数)类的实现,它在这种情况下似乎是一个有用的解决方案。

问题是其中一个类使用std::map ,就我而言,这是一个不透明的类。 我当然不认为我可以memcpy()它。 在任何情况下我都可能无法使用std :: map。 据我所知,它可以分配几块内存。

我能想到的最好的解决方法很简单。 由于碎片化的内存管理器将新的分配放在更有利的位置,我需要做的就是重新分配它然后删除旧的:

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



无论如何,这让我想知道:

C ++是否具有将对象移动/复制到特定内存位置的语义或习语?

是否可以将stl容器的内容移动到特定的内存位置?


编辑:虽然我没有指出,我显然会将一个allocator参数传递给std :: map。 基于我得到的信息性答案,我意识到我在初始问题中发布的解决方法可能是减少碎片的唯一方法。 通过使用map的复制构造函数(和allocator模板参数),可以正确地重新分配映射使用的所有内存。

正如评论所指出的,这主要是一个理论问题。 内存碎片很少需要担心。

每次插入新键,值对时,映射都会分配一个节点来存储它。 这种分配如何发生的细节由地图使用的分配器决定。

默认情况下,在std::map<K,V>创建映射时std::map<K,V>将使用默认分配器,它在堆上创建节点(即使用new / delete )。

您不希望如此,因此您必须创建一个自定义分配器类,该类根据内存管理器的要求创建节点。

创建一个allocator类并不简单。 此代码显示了如何完成,您必须根据自己的需要进行调整。

一旦你有了你的分配器类(假设你称之为MemManagerAllocator ),你必须将你的地图定义为std::map<K, V, MemManagerAllocator> ,然后像使用常规地图一样使用它。

就个人而言,我需要有一个非常糟糕的内存碎片问题才能解决所有麻烦。

C ++对象的内容将分散在堆中。 STL对象(例如容器或字符串等)可能会将其元数据存储在堆栈中(如果不将其放在动态内存中)......但是内容会分散在堆中。

跟踪对象的所有元素以及对这些元素的所有引用将是一项艰巨的任务。 语言必须提供某种形式的“钩子”或事件,以便跟踪记忆块之间的关系。

所以不,你不能只记忆一个任意的STL对象。

Afaik压倒新的不是灵丹妙药,它是一个“进程全局”概念,因此尝试将新闻本地化为线程 - 对象 - 分配对是不可能的。 这种本地化将使您能够将内存组合在一起。

您可以编写自己的容器,显式地使用自定义内存分配器(显式,因为您提供了必要的对象标识信息),并且有一些自定义分配器。

您可以使用新的展示位置?

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它。

您没有提到您正在编码的平台,或者是否允许这样做。 但是在Linux和GCC中,C ++默认分配器是用malloc实现的。

malloc可以被覆盖并替换为您自己的内部分配器。

我会按如下方式实现这个malloc

在一般情况下,只需遵循原始的malloc 无论何时,您都可以更改malloc函数的行为,以返回指向您准备的特殊内存区域的指针。

因此,在创建这个特定的std::map你会给malloc一个提示。 (通过全局变量或其他一些通信手段。)

更新:alemjerus建议实现std::map::allocator ,这是一个清晰的方式在同一主题,也是平台无关。

您可以使用placement new来定义base std :: map对象所在的位置。 但是大部分空间将通过std :: map在堆上分配。

暂无
暂无

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

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