【问题标题】:Calculate allocated memory of std::string (and the use of strings in std::vector)计算 std::string 的分配内存(以及 std::vector 中字符串的使用)
【发布时间】:2019-01-17 13:52:51
【问题描述】:

我想计算在创建字符串并将值分配给字符串时分配了多少内存。

string s = "";
cout << sizeof(s) << endl;
cout << sizeof(s.at(0)) * s.capacity() << endl;
s = "1234567890qwertz";
cout << sizeof(s) << endl;
cout << sizeof(s.at(0)) * s.capacity() << endl;

这是我的字符串 s 消耗的所有内存吗?我通过简单地调用 sizeof(s) 得到的初始/静态部分(在我的机器上是 40 个字节)加上动态部分 - 一个字符的大小乘以分配的占位符,以使字符串有效地调整大小(在我的机器上,字符串 s 首先分配了一个 15 字节的块,直到文本太长为止,所以在第二次分配之后,动态部分是 31 字节)。顺便说一句,为什么不是 16 和 32 字节?

这种思考方式(每个字符串的静态+动态是它占用的所有内存)正确吗?

意思是如果我有一个 std::vector 字符串,并且我想计算该向量的所有内存,我需要做同样的事情:我添加我的初始/静态大小向量得到加动态部分,这意味着一个字符串占用的总内存,就像我在上面对向量内的每个字符串做的那样?

vector<string> cache;
// fill cache with strings of dynamic length
int size = sizeof(cache);
for (int i = 0; i < cache.size(); i++)
{
    size += sizeof(cache[i]);
    size += sizeof(cache[i].at(0)) * cache[i].capacity();
}

所以总结一下,我的“缓存”占用的内存量是正确的吗?

编辑: 或者我是否还需要考虑到 std::vector 本身也有一个 .capacity() >= .size() 这可能意味着我实际上需要这样做:

对于每个cache.capacity() - 我需要添加sizeof(cache[i]) 和另外 对于每个cache.size() - 添加sizeof(cache[i].at(0)) * cache[i].capacity() ??

【问题讨论】:

  • 我想计算在创建字符串并将值分配给字符串时分配了多少内存 -- 好的,我会问。为什么需要这些信息?
  • sizeof(s)object s 的大小,而不是字符串本身。除非有一些短字符串优化(将内容存储在实际字符串对象中),否则 std::string 实际上只不过是几个大小和一个指向实际字符串数据的指针。
  • @huzzm 是的,虽然有些字符串可能根本不分配内存。
  • @huzzm 全局/静态字符串,小字符串优化。

标签: c++ string memory sizeof allocation


【解决方案1】:

这个问题很难回答。天真地你会认为消耗的内存总量是

vector_capacity * sizeof(std::string) + sum_of_capacity_of_each_string_in_the_vector

但这更多的是一个上限,而不是实际可以消耗的量。例如,short string optimization 允许 std::string 将字符串数据存储在字符串对象本身消耗的存储空间中(您称之为静态大小)。如果是这种情况,那么实际消耗的空间将是

vector_capacity * sizeof(std::string)

向量中每个字符串的容量就是你在不分配任何额外空间的情况下占用了多少空间。您将需要检查您的实现以查看它是否使用 SSO 和长字符串,它将存储在字符串对象中,以实际了解容量值是使用字符串内部空间还是实际消耗额外内存。这使得实际空间消耗

vector_capacity * sizeof(std::string) + sum_of_capacity_of_each_string_in_the_vector_where_
                                        the_capcity_is_more_than_the_sso_amount

在你计算sizeof(cache[i].at(0)) 是不需要的。 std::string 使用charsizeof(char) 保证为1

【讨论】:

  • 非常感谢。这就是我一直在寻找的答案。
  • 您本身不需要实现细节;您只需要知道字符串何时分配新内存。这可以通过例如using a custom allocator.
  • 我再次编辑了这个问题,因为向量也有容量 >= 大小。这是否会改变任何内容或容量为 15 而向量内只有 3 个字符串意味着它实际上是 15 * sizeof(string) + 3 * 每个单个字符串的动态内存(容量 * char 大小)
  • @BartekBanachewicz 好的。谢谢!
  • @huzzm 确实如此。我已经更新了答案以使用vector_capacity * sizeof(std::string)
【解决方案2】:

字符串的容量比你预期的少一个原因很简单,那就是

s.c_str()

C++ 字符串存储在一块内存中,其容量给出了已用空间的总大小和大小。但是一个 C 字符串是 0 终止的。 C++ 字符串在内存块的末尾保留一个额外的字节来存储一个 0。这样s.c_str() 总是以 0 结尾。

所以字符串的动态部分使用的内存是容量+1。

关于字符串或字符串向量消耗的总内存,NathanOliver 回答说我认为。但要注意向量多次持有同一个字符串。

【讨论】:

  • 哦,是的,非常正确。我忘记了空终止。感谢您的额外回答!
【解决方案3】:

如果您想知道您的std::vector&lt;std::string&gt; 使用了多少空间,请计算一下:

auto netto_memory_use(std::vector<std::string> const& x) noexcept {
    return std::accumulate(
        begin(x),
        end(x),
        sizeof x + sizeof x[0] * x.capacity(),
        [](auto n, auto&& s) {
            if (std::less<void*>()(data(s), &s)
            || std::greater_eq<void*>()(data(s) + s.capacity(), &s + 1))
                return n + s.capacity() + 1;
            return n;
        });
    }

我使用std::less&lt;void*&gt; / std::greater_eq&lt;void*&gt; 来利用它们定义一个完整的订单,而不是只使用比较运算符。

累加器在添加字符串容量之前测试应用的小字符串优化 (SSO)。当然,所有容量为 0 的字符串可以共享相同的静态分配终止符。或者容量和/或长度可以与字符数据一起分配。
不过,除了内存管理系统开销之外,这应该是所用内存的一个很好的近似值。

【讨论】:

  • 什么是data()
  • @Bouncner std::data() 根据 ADL 找到。
猜你喜欢
  • 2011-01-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-10-08
  • 2020-10-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多