计算 std::string 的分配内存(以及 std::vector 中字符串的使用)
Calculate allocated memory of std::string (and the use of strings in std::vector)
我想计算在创建字符串并为其赋值时分配了多少内存。
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;
这是我的字符串消耗的所有内存吗?我通过简单地调用 sizeof(s) (在我的机器上是 40 个字节)得到的 initial/static 部分 plus 动态部分 - 一个字符的大小乘以分配的占位符使字符串可以有效地调整大小(在我的机器上,字符串 s 首先分配一个 15 字节的块,直到文本太长,所以在第二次分配之后,动态部分为 31 字节)。为什么不是 16 和 32 字节呢?
这种思路(static + dynamic for each string is all the memory it occurs)是否正确?
意味着如果我有一个 std::vector 字符串,并且我想计算该向量的所有内存,我需要做同样的事情:我添加 initial/static 我的向量的大小加上动态部分,这意味着一个字符串占用的总内存,就像我上面对向量中的每个字符串所做的那样?
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();
}
总而言之,我的 "cache" 占用的内存量是否正确?
编辑:
或者我还需要考虑 std::vector 本身也有 .capacity() >= .size() 这可能意味着我实际上需要这样做:
对于每个 cache.capacity()
- 我需要添加 sizeof(cache[i])
并且另外
对于每个 cache.size()
- 添加 sizeof(cache[i].at(0)) * cache[i].capacity()
??
这个问题很难回答。天真地你会认为消耗的内存总量是
vector_capacity * sizeof(std::string) + sum_of_capacity_of_each_string_in_the_vector
但这更多的是一个上限,并不是真正能够消耗的。例如,short string optimization 允许 std::string
将字符串数据存储在字符串对象本身消耗的存储空间中(您称之为静态大小)。如果是这样,那么实际消耗的 space 将是
vector_capacity * sizeof(std::string)
向量中每个字符串的容量就是您在不分配任何额外 space 的情况下占用了多少 space。您将需要检查您的实现以查看它是否使用 SSO 以及它将存储在字符串对象中的字符串的长度,以实际了解容量值是使用内部字符串 space 还是实际消耗额外的内存。这使得实际 space 消耗
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
使用 char
并且 sizeof(char)
保证是 1
字符串的容量比你想象的少一个,原因很简单,那就是
s.c_str()
一个 C++ 字符串存储在一个内存块中,其容量给出了总大小和使用的大小 space。但是 C 字符串以 0 终止。 C++ 字符串在内存块的末尾保留一个额外的字节来存储 0。这样 s.c_str()
总是以 0 终止。
所以字符串动态部分使用的内存是capacity + 1。
关于字符串或字符串向量消耗的总内存,NathanOliver 回答说我认为。但要注意多次持有相同字符串的向量。
如果您想知道您的 std::vector<std::string>
使用了多少 space,请计算它:
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<void*>
/ std::greater_eq<void*>
来利用它们定义完整的顺序,而不是仅使用比较运算符。
累加器在添加字符串的容量之前测试应用的小字符串优化 (SSO)。当然,所有容量为 0 的字符串都可以共享同一个静态分配的终止符。或者 capacity and/or length 可以和 character-data 一起分配。
尽管如此,除了内存管理系统开销之外,这应该是所用内存的一个很好的近似值。
我想计算在创建字符串并为其赋值时分配了多少内存。
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;
这是我的字符串消耗的所有内存吗?我通过简单地调用 sizeof(s) (在我的机器上是 40 个字节)得到的 initial/static 部分 plus 动态部分 - 一个字符的大小乘以分配的占位符使字符串可以有效地调整大小(在我的机器上,字符串 s 首先分配一个 15 字节的块,直到文本太长,所以在第二次分配之后,动态部分为 31 字节)。为什么不是 16 和 32 字节呢?
这种思路(static + dynamic for each string is all the memory it occurs)是否正确?
意味着如果我有一个 std::vector 字符串,并且我想计算该向量的所有内存,我需要做同样的事情:我添加 initial/static 我的向量的大小加上动态部分,这意味着一个字符串占用的总内存,就像我上面对向量中的每个字符串所做的那样?
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();
}
总而言之,我的 "cache" 占用的内存量是否正确?
编辑: 或者我还需要考虑 std::vector 本身也有 .capacity() >= .size() 这可能意味着我实际上需要这样做:
对于每个 cache.capacity()
- 我需要添加 sizeof(cache[i])
并且另外
对于每个 cache.size()
- 添加 sizeof(cache[i].at(0)) * cache[i].capacity()
??
这个问题很难回答。天真地你会认为消耗的内存总量是
vector_capacity * sizeof(std::string) + sum_of_capacity_of_each_string_in_the_vector
但这更多的是一个上限,并不是真正能够消耗的。例如,short string optimization 允许 std::string
将字符串数据存储在字符串对象本身消耗的存储空间中(您称之为静态大小)。如果是这样,那么实际消耗的 space 将是
vector_capacity * sizeof(std::string)
向量中每个字符串的容量就是您在不分配任何额外 space 的情况下占用了多少 space。您将需要检查您的实现以查看它是否使用 SSO 以及它将存储在字符串对象中的字符串的长度,以实际了解容量值是使用内部字符串 space 还是实际消耗额外的内存。这使得实际 space 消耗
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
使用 char
并且 sizeof(char)
保证是 1
字符串的容量比你想象的少一个,原因很简单,那就是
s.c_str()
一个 C++ 字符串存储在一个内存块中,其容量给出了总大小和使用的大小 space。但是 C 字符串以 0 终止。 C++ 字符串在内存块的末尾保留一个额外的字节来存储 0。这样 s.c_str()
总是以 0 终止。
所以字符串动态部分使用的内存是capacity + 1。
关于字符串或字符串向量消耗的总内存,NathanOliver 回答说我认为。但要注意多次持有相同字符串的向量。
如果您想知道您的 std::vector<std::string>
使用了多少 space,请计算它:
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<void*>
/ std::greater_eq<void*>
来利用它们定义完整的顺序,而不是仅使用比较运算符。
累加器在添加字符串的容量之前测试应用的小字符串优化 (SSO)。当然,所有容量为 0 的字符串都可以共享同一个静态分配的终止符。或者 capacity and/or length 可以和 character-data 一起分配。
尽管如此,除了内存管理系统开销之外,这应该是所用内存的一个很好的近似值。