考虑以下测试程序:
#include <iostream>
#include <string>
#include <vector>
int main()
{
std::cout << sizeof(std::string("hi")) << " ";
std::string a[10];
std::cout << sizeof(a) << " ";
std::vector<std::string> v(10);
std::cout << sizeof(v) + sizeof(std::string) * v.capacity() << "\n";
}
libstdc和libc的输出分别为:
8 80 104
24 240 264
如您所见,libc
占用的内存是一个简单程序的3倍。导致这种内存差异的实现有何不同?我需要担心吗?我如何解决它?
摘要:看起来libstdc
只使用了一个char*
。事实上,它分配了更多的内存。
因此,您不应该担心Clang的libc
实现内存效率低下。
根据libstdc的文件(详细描述):
A string looks like this:
[_Rep]
_M_length
[basic_string<char_type>] _M_capacity
_M_dataplus _M_refcount
_M_p ----------------> unnamed array of char_type
其中,M p指向字符串中的第一个字符,将其转换为指向-u Rep的指针,然后减去1以获得指向标头的指针。
这种方法具有巨大的优势,一个字符串对象只需要一次分配。所有的丑陋都局限在一对内联函数中,每个内联函数都编译成一条add指令:_Rep::u M_data()和字符串::u M_Rep();以及分配函数,该函数获取一块原始字节并具有足够的空间,并在前端构造一个_Rep对象。
您希望\u M\u数据指向字符数组而不是\u Rep的原因是,调试器可以看到字符串内容。(可能我们应该添加一个非内联成员来获取调试器要使用的\u Rep,这样用户就可以检查实际的字符串长度。)
因此,它看起来就像一个char*
,但这在内存使用方面具有误导性。
以前,libstdc主要使用这种布局:
struct _Rep_base
{
size_type _M_length;
size_type _M_capacity;
_Atomic_word _M_refcount;
};
这更接近libc的结果。
libc
使用了"短字符串优化",确切的布局取决于是否定义了_LIBCPP_ABI_ALTERNATE_STRING_LAYOUT
,如果定义了,如果字符串短,数据指针将是字对齐的,详情见源代码。
短字符串优化避免了堆分配,因此如果只考虑堆栈上分配的部分,它看起来比libstdc
实现更昂贵。sizeof(std::string)
仅显示堆栈使用情况,而不是整体内存使用情况(堆栈堆)。
您不必担心,标准库实现者知道他们在做什么。
使用来自GCC subversion中继的最新代码libstdc给出了这些数字:
32 320 344
这是因为几周前,我切换了默认的std::string
实现,以使用小字符串优化(空间为15个字符),而不是您测试的写时复制实现。
这里有一个简短的程序,可以帮助您探索std::string的两种内存使用:堆栈和堆。
#include <string>
#include <new>
#include <cstdio>
#include <cstdlib>
std::size_t allocated = 0;
void* operator new (size_t sz)
{
void* p = std::malloc(sz);
allocated += sz;
return p;
}
void operator delete(void* p) noexcept
{
return std::free(p);
}
int
main()
{
allocated = 0;
std::string s("hi");
std::printf("stack space = %zu, heap space = %zu, capacity = %zu\n",
sizeof(s), allocated, s.capacity());
}
使用http://melpon.org/wandbox/很容易获得不同编译器/库组合的输出,例如:
gcc 4.9.1:
stack space = 8, heap space = 27, capacity = 2
gcc 5.0.0:
stack space = 32, heap space = 0, capacity = 15
clang/libc:
stack space = 24, heap space = 0, capacity = 22
VS-2015:
stack space = 32, heap space = 0, capacity = 15
(最后一行来自http://webcompiler.cloudapp.net)
上面的输出还显示了容量,这是衡量字符串在必须从堆中分配新的、更大的缓冲区之前可以容纳多少个字符。对于gcc-5.0、libc和VS-2015实现,这是对短字符串缓冲区的度量。也就是说,在堆栈上分配的大小缓冲区用于容纳短字符串,从而避免了更昂贵的堆分配。
在短字符串实现中,libc实现的(堆栈使用率)似乎最小,但包含最大的短字符串缓冲区。如果计算总内存使用量(堆栈堆),在所有4种实现中,libc对这个2字符字符串的总内存使用量最小。
应该注意的是,所有这些测量都是在64位平台上进行的。在32位上,libc堆栈的使用率将下降到12,小字符串缓冲区将下降到10。我不知道32位平台上其他实现的行为,但您可以使用上面的代码来了解。
考虑以下代码片段: > 带有的G9未能编译代码,错误如下: /opt/compiler explorer/gcc-trunk-20180711/include/c/9.0.0/variant:94:29:错误:嵌套名称说明符中使用的类型“std::variant_size”不完整 godbolt上的活生生的例子。组织 > 如果不是,这里什么实现是正确的,为什么?
问题内容: 我正在使用c / c 为osx和linux开发命令行界面可执行文件。该项目将链接到opencv。我应该使用libc 还是libstdc ++? 问题答案: 我会为每个操作系统使用本机库,即GNU / Linux上的libstdc 和Mac OS X上的libc 。 libc 在GNU / Linux上不是100%完整的,而libstdc 更完整时使用libc并没有真正的优势。另外,如果
问题内容: 这最终会消耗我所有的可用内存,然后进程被杀死。我曾尝试将标签从更改为“较小”标签,但这并没有什么不同。 我在做什么错/如何处理这个大文件? 我可以轻松地将其切碎并以较小的块进行处理,但这比我想要的还要难看。 问题答案: 当遍历整个文件时,将构建一棵树,并且不会释放任何元素。这样做的好处是元素可以记住其父元素是谁,并且您可以形成引用祖先元素的XPath。缺点是它会消耗大量内存。 为了在解
我的问题作为标题,通过搜索得到了一些知识: > Linux具有共享内存如何测量应用程序或进程的实际内存使用情况? JVM将保留在Xms中设置的内存量,对于堆内存,-Xms JVM是什么意思? 下面是我在Ubuntu12.04(64bit)JDK 1.7.0_04上的测试运行。和顶部显示如下:
P0137 引入了函数模板 ,并在有关联合、生存期和指针的部分中对标准进行了许多更改。 这篇论文解决的问题是什么?我需要注意的语言变化是什么?我们在清洗什么?
本文向大家介绍String 为什 么是不可变的?相关面试题,主要包含被问及String 为什 么是不可变的?时的应答技巧和注意事项,需要的朋友参考一下 简单的来说:String 类中使用 final 关键字修饰字符数组来保存字符串,`private final char value[]`,所以 String 对象是不可变的。而StringBuilder 与 StringBuffer 都继承自 Ab