假设MyClass
的大小为N
字节,我将M
MyClass
个std::set<MyClass>
对象放入N*M
。理论内存开销是std::set
字节,但据我所知,set
是使用树结构实现的,所以我认为必须有额外的内存开销。如何估计{{1}}的近似合理内存成本,因为当我运行程序时,内存成本高于我的预期?
答案 0 :(得分:3)
如@SirDarius所述,这是依赖于实现的,因此您需要检查每个实现。
通常,std::set
实现为带有精益迭代器的红黑树。这意味着对于集合中的每个元素,都有一个节点,并且此节点大致包含:
因此,{64}平台上此节点的最小足迹是footprint(node)
:
sizeof(MyClass)
,舍入为8个字节(出于对齐原因:查找&#34; struct padding&#34;) 注意:很容易在某处使用未使用的位来隐藏红/黑标志而无需额外费用,例如考虑到给定节点对齐指针的最低有效位总是这样的事实0
,或插入MyClass
填充(如果有的话)。
然而,当你通过T
分配一个对象new
时({1}}在幕后做了什么,以及它本身使用std::allocator
除非超载),否则不分配只 malloc
字节:
sizeof(T)
的典型实现使用 size buckets ,这意味着如果在分配9字节对象时有8个字节桶和16个字节桶,则会进入16字节桶(浪费7个字节)因此,确实使用malloc
很可能会消耗更多而不仅仅是set
,尽管开销取决于您的标准库实现。对于小型对象(例如set.size() * sizeof(MyClass)
),这种开销可能很大:在64位平台上,您至少看到+ 500%的开销),因为将节点链接在一起的成本通常是固定的,而对于大型物体可能不会引人注意。
为了减少开销,您通常使用数组。这就是B-Tree所做的事情,尽管它是以稳定性为代价的(即每个元素都停留在固定的内存地址而不管其他内容发生了什么)。
答案 1 :(得分:1)
有序关联容器具有约束,这几乎要求它们被实现为平衡树。很可能每棵树中的节点都有两个指向子节点的指针和一个指向父节点的指针。根据增量是否在指针中存储比特技巧以存储附加信息,在分配的节点中可能存在额外的字。此外,存储器管理系统可以为每个分配的存储器块存储一个字,并将其对准例如16字节边界。
实现的实际操作当然没有在标准中指定,但我认为M
大小为N
的元素的最小内存消耗为
M * (N + 2 * sizeof(void*) + sizeof(int))
可能更多:我可能也会使用指向父级的指针。