64 位计算机上的 STL 矢量大小

stl vector size on 64-bit machines

本文关键字:STL 计算机      更新时间:2023-10-16

我有一个将使用数百万个向量的应用程序。

似乎 std::vector 的大多数实现都使用 4 个指针(_First、_Last、_End 和 _Alloc),在 64 位机器上消耗 32 个字节。 对于矢量的大多数"实际"用例,人们可能会使用单个指针和两个"无符号 int"字段分别存储当前大小和分配大小。 忽略支持自定义分配的潜在挑战(而不是假设分配必须通过全局 new &delete 运算符),似乎可以构建一个仅使用 16 个字节(或者最坏的情况是 24 个字节来支持 _Alloc 指针)的符合 STL 的向量类。

在我开始编写代码之前,1)我应该注意任何陷阱吗?2)是否存在开源实现?

你可以完成这样的事情 - 但你不太可能获得那么多。

首先是性能方面。您正在用时间来换取内存消耗。无论您保存什么内存,都必须在每次调用end时进行加法和乘法(好吧,如果它是一个可以优化sizeof(vector<t>::value_type) == 1乘法的向量)。请注意,大多数基于向量的手写循环代码在每次循环迭代中都会调用end。在现代CPU上,这实际上将是一个重大胜利,因为它允许处理器在缓存中保留更多内容;除非内部循环中的那几条额外指令迫使处理器过于频繁地交换指令缓存中的内容)

此外,就

矢量中的总体内存使用而言,内存节省可能很小,原因如下:

  • 内存管理器开销。在大多数内存管理器实现中,来自内存管理器的每个分配(当然需要哪个向量)都会增加 16-24 字节的开销。(假设像dlmalloc(UNIX/Linux/等)或RtlHeap(Windows))
  • 过度配置负载。为了实现最后的摊销常量插入和删除,当向量调整大小时,它的大小调整为向量中数据大小的某个倍数。这意味着向量分配的典型内存容量足以满足向量中实际存储的元素数的 1.6 (MSVC++) 或 2 (STLPort, libstdc++) 倍数。
  • 对齐限制。如果要将这许多向量放入数组(或其他向量)中,请记住,该向量的第一个成员仍然是指向分配的内存块的指针。无论如何,此指针通常需要 8 个字节对齐 - 因此您保存的 4 个字节将丢失到数组中的结构填充中。

我现在将使用矢量的简单实现。如果您通过内存探查器运行代码,并发现通过删除这两个指针可以节省大量成本,那么您可能正在实现自己的优化类,该类符合您的性能特征,而不是依赖于内置的矢量实现。(在实现小字符串优化的平台上std::string此类优化类的示例)

(注意:据我所知,唯一优化Alloc指针的编译器是VC11,它尚未发布。虽然 Nim 说当前的 libstdc++ 预发布版本也可以这样做......

除非这些向量的内容非常小,否则保存内容的 16 字节与 32 字节之间的差异将只占它们消耗的总内存的一小部分。重新发明这个轮子需要付出很多努力,所以请确保你为所有这些工作获得足够的回报。

顺便说一句,教育也有价值,这样做你会学到很多东西。如果您选择继续,您可以考虑先编写一个测试套件,然后在当前实现上练习它,然后在您发明的实现上练习它。

要回答是否值得付出努力,请找到或编写适合需求的兼容实现(也许 std::vector 中还有其他您不需要的东西),并将性能与相关平台上的std::vector<your_type>进行比较。您的建议至少可以提高移动构造函数以及移动赋值运算符的性能:

typedef int32_t v4si __attribute__ ((vector_size (16)));
union
    {
    v4si data;
    struct
        {
        T* pointer;
        uint32_t length;
        uint32_t capacity;
        } content;
    } m_data;

这仅涵盖"理智"T(除了移动语义)。 https://godbolt.org/g/d5yU3o