例如,我有一个已知sizeof(A)和sizeof(B)的std :: map,而map里面有N个条目。你会如何估计它的内存使用量? 我会说它就像
(sizeof(A) + sizeof(B)) * N * factor
但是因素是什么?不同的公式可能吗?
也许要求上限更容易?
答案 0 :(得分:35)
估计值将更接近
(sizeof(A) + sizeof(B) + ELEMENT_OVERHEAD) * N + CONTAINER_OVERHEAD
您添加的每个元素都有开销,并且还有一个固定的开销用于维护用于存储映射的数据结构的数据结构。这通常是二叉树,例如Red-Black Tree。例如,在GCC C ++中,STL实现ELEMENT_OVERHEAD
将是sizeof(_Rb_tree_node_base)
而CONTAINER_OVERHEAD
将是sizeof(_Rb_tree)
。对于上图,您还应该添加用于存储地图元素的内存管理结构的开销。
通过测量代码对各种大型集合的内存消耗来估算可能更容易。
答案 1 :(得分:17)
你可以使用Curtis Bartley的MemTrack。它是一个内存分配器,它取代了默认值,可以跟踪内存使用情况,直到分配类型。
输出示例:
-----------------------
Memory Usage Statistics
-----------------------
allocated type blocks bytes
-------------- ------ -----
struct FHRDocPath::IndexedRec 11031 13.7% 2756600 45.8%
class FHRDocPath 10734 13.3% 772848 12.8%
class FHRDocElemPropLst 13132 16.3% 420224 7.0%
struct FHRDocVDict::IndexedRec 3595 4.5% 370336 6.2%
struct FHRDocMDict::IndexedRec 13368 16.6% 208200 3.5%
class FHRDocObject * 36 0.0% 172836 2.9%
struct FHRDocData::IndexedRec 890 1.1% 159880 2.7%
struct FHRDocLineTable::IndexedRec 408 0.5% 152824 2.5%
struct FHRDocMList::IndexedRec 2656 3.3% 119168 2.0%
class FHRDocMList 1964 2.4% 62848 1.0%
class FHRDocVMpObj 2096 2.6% 58688 1.0%
class FHRDocProcessColor 1259 1.6% 50360 0.8%
struct FHRDocTextBlok::IndexedRec 680 0.8% 48756 0.8%
class FHRDocUString 1800 2.2% 43200 0.7%
class FHRDocGroup 684 0.8% 41040 0.7%
class FHRDocObject * (__cdecl*)(void) 36 0.0% 39928 0.7%
class FHRDocXform 516 0.6% 35088 0.6%
class FHRDocTextColumn 403 0.5% 33852 0.6%
class FHRDocTString 407 0.5% 29304 0.5%
struct FHRDocUString::IndexedRec 1800 2.2% 27904 0.5%
答案 2 :(得分:14)
如果您真的想知道运行时内存占用量,请使用自定义分配器并在创建映射时将其传递给它。请参阅Josuttis的书籍和他的this页面(针对自定义分配器)。
也许要求上限更容易?
上限取决于确切的实现(例如,使用的平衡树的特定变体)。也许,您可以告诉我们为什么您需要这些信息,以便我们能够提供更好的帮助?
答案 3 :(得分:7)
我最近需要自己回答这个问题,并简单地使用在MSVC 2012下以64位模式编译的std :: map编写了一个小的基准程序。
一个有1.5亿个节点的地图浸泡了〜15GB,这意味着8字节L,8字节R,8字节int键和8字节数据,总共32字节,吸收约2/3 map为内部节点的内存,留下1/3的叶子。
就个人而言,我发现这个内存效率出乎意料地差,但它就是它的本质。
希望这是一个方便的经验法则。
PS:std :: map的开销是单个节点大小AFAICT的开销。
答案 4 :(得分:0)
公式更像是:
(sizeof(A) + sizeof(B) + factor) * N
其中factor是每个条目的开销。 C ++地图通常实现为红黑树。这些是二叉树,因此左/右节点至少有两个指针。还会有一些实现内容 - 可能是父指针和“颜色”指示符,因此因素可能类似于
(sizeof( RBNode *) * 3 + 1) / 2
但是,所有这些都是高度依赖于实现的 - 要确定您确实需要检查自己的库实现的代码。
答案 5 :(得分:0)
我也在寻找某种方法来计算std::map
的大小。我尝试了Diomidis Spinellis的答案中所解释的内容,并在此扩展了他的答案,这可能会对其他人有所帮助。
我通过添加几行代码来扩展他的答案。
#include <bits/stl_tree.h>
int main(int argc, char *argv[])
{
std::cout << sizeof(std::_Rb_tree_node_base) << std::endl;
return 0;
}
输出(在运行Linux [4.9.175]和编译器:arm-fslc-linux-gnueabi-gcc (GCC) 7.3.0
的ARM Cortex A-9 iMX6Solo-X处理器上):
16
考虑到std::map<A, B>
,我对ELEMENT_OVERHEAD
的大小感兴趣,因为它随着地图中元素的数量线性增长。发现ELEMENT_OVERHEAD与sizeof(std::_Rb_tree_node_base)
等效,因此对于我的系统,其值为16。
(sizeof(A) + sizeof(B) + ELEMENT_OVERHEAD) * N + CONTAINER_OVERHEAD
答案 6 :(得分:-1)
地图的大小实际上取决于地图的实现。您可能在不同的编译器/平台上具有不同的大小,具体取决于它们提供的STL实现。
为什么你需要这个尺寸?