【问题标题】:stl vector size on 64-bit machines64 位机器上的 stl 向量大小
【发布时间】:2012-07-02 14:23:28
【问题描述】:

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

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

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

【问题讨论】:

  • 向量是否相互关联?就像,它们是矩阵中的行吗?如果是这样,您可以应用其他不需要重新实现 std::vector 的优化。
  • 对我来说听起来像是过早的优化。编写应用程序逻辑,然后,如果向量开销的大小是一个问题,请查看解决方案。
  • 您可以考虑一下您的内存使用配置文件,并尝试比一百万个向量更有效地安排它。他们都需要独立成长吗?无法预测它们的大小吗?
  • “我有一个将使用数百万个向量的应用程序” - 哇,您真的需要完全动态地独立调整每个向量的大小吗?听起来像是数据结构重新设计的一个很好的起点。这不仅可以减少整体大小,还可以提高性能,当使用更多的本地化数据而不是为每一小串数字(或其中的任何内容)使用完全不同的内存区域时,虽然我不知道你的潜在问题,也许你真的需要数百万std::vectors。
  • @DavidRodríguez-dribeas: capacity() 如果在这个意义上使用将是size_t,它与指针的宽度相同。 (所以即使它不是指针,在大小方面它也与指针相同)_Last 将与存储 capacity() 相同(也就是说,_Lastbegin()+capacity())第四个指针指向分配器。

标签: c++ stl vector


【解决方案1】:

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

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

此外,就向量中的整体内存使用而言,内存节省可能很小,原因如下:

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

我现在会使用 vector 的简单实现。如果您通过内存分析器运行代码并发现摆脱这两个指针可以节省大量资金,那么您可能会实现自己的优化类来满足您的性能特征,而不是依赖于内置的矢量实现。 (一个这样的优化类的例子是std::string 在那些实现小字符串优化的平台上)

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

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

      【解决方案3】:

      要回答是否值得付出努力,请找到或编写一个符合您的需求的兼容实现(也许 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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-02-05
        • 1970-01-01
        • 2019-08-21
        • 2014-01-10
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多