为什么 C++ 的初始分配比 C 的大得多?
Why is C++ initial allocation so much larger than C's?
当使用相同的代码时,只需更改编译器(从 C 编译器到 C++ 编译器)就会改变分配的内存量。我不太确定为什么会这样,并且想更多地了解它。到目前为止,我得到的最好的回应是 "probably the I/O streams",它的描述性不强,让我想知道 C++ 的 "you don't pay for what you don't use" 方面。
我使用的是 Clang 和 GCC 编译器,版本分别为 7.0.1-8 和 8.3.0-6。我的系统 运行ning 在 Debian 10 (Buster) 上,最新。基准测试是通过 Valgrind Massif 完成的。
#include <stdio.h>
int main() {
printf("Hello, world!\n");
return 0;
}
使用的代码没有改变,但无论我编译为 C 还是 C++,它都会改变 Valgrind 基准测试的结果。但是,这些值在编译器之间保持一致。 运行程序的时间分配(峰值)如下:
- GCC (C):1,032 字节 (1 KB)
- G++ (C++):73,744 字节,(~74 KB)
- Clang (C):1,032 字节 (1 KB)
- Clang++ (C++):73,744 字节(~74 KB)
为了编译,我使用了以下命令:
clang -O3 -o c-clang ./main.c
gcc -O3 -o c-gcc ./main.c
clang++ -O3 -o cpp-clang ./main.cpp
g++ -O3 -o cpp-gcc ./main.cpp
对于 Valgrind,我在每个编译器和语言上 运行 valgrind --tool=massif --massif-out-file=m_compiler_lang ./compiler-lang
,然后 ms_print
用于显示峰值。
我是不是做错了什么?
堆使用来自C++标准库。它在启动时分配内存供内部库使用。如果你不 link 反对它,C 和 C++ 版本之间应该有零差异。使用 GCC 和 Clang,您可以使用以下命令编译文件:
g++ -Wl,--as-needed main.cpp
这将指示 linker 不要 link 反对未使用的库。在您的示例代码中,没有使用 C++ 库,因此它不应该 link 针对 C++ 标准库。
您也可以使用 C 文件进行测试。如果你编译:
gcc main.c -lstdc++
堆使用情况将重新出现,即使您已经构建了 C 程序。
堆的使用显然取决于您使用的特定 C++ 库实现。在你的例子中,那是 GNU C++ 库,libstdc++. Other implementations might not allocate the same amount of memory, or they might not allocate any memory at all (at least not on startup.) The LLVM C++ library (libc++) 例如在启动时不进行堆分配,至少在我的 Linux 机器上是这样:
clang++ -stdlib=libc++ main.cpp
堆的使用与完全不link一样。
(如果编译失败,则可能是libc++没有安装,包名一般包含"libc++"或"libcxx"。)
GCC 和 Clang 都不是编译器——它们实际上是工具链驱动程序。这意味着它们调用编译器、汇编器和链接器。
如果您使用 C 或 C++ 编译器编译代码,您将得到相同的程序集。汇编程序将生成相同的对象。不同之处在于,工具链驱动程序将为两种不同的语言提供不同的输入到链接器:不同的启动(C++ 需要代码为在命名空间级别具有静态或 thread-local 存储持续时间的对象执行构造函数和析构函数,并且需要基础结构例如,用于在异常处理期间支持展开的堆栈帧)、C++ 标准库(在名称空间级别也有静态存储持续时间的对象),以及可能的其他运行时库(例如,libgcc 及其 stack-unwinding 基础设施).
简而言之,导致占用空间增加的不是编译器,而是您通过选择 C++ 语言选择使用的内容的链接。
C++ 确实具有 "pay only for what you use" 哲学,但使用该语言需要付出代价。您可以禁用部分语言(RTTI、异常处理),但您不再使用 C++。正如另一个答案中提到的,如果您根本不使用标准库,您可以指示驱动程序将其省略 (--Wl,--as-needed) 但如果您不打算使用任何C++ 或其库的特性,你为什么还要选择 C++ 作为编程语言?
当使用相同的代码时,只需更改编译器(从 C 编译器到 C++ 编译器)就会改变分配的内存量。我不太确定为什么会这样,并且想更多地了解它。到目前为止,我得到的最好的回应是 "probably the I/O streams",它的描述性不强,让我想知道 C++ 的 "you don't pay for what you don't use" 方面。
我使用的是 Clang 和 GCC 编译器,版本分别为 7.0.1-8 和 8.3.0-6。我的系统 运行ning 在 Debian 10 (Buster) 上,最新。基准测试是通过 Valgrind Massif 完成的。
#include <stdio.h>
int main() {
printf("Hello, world!\n");
return 0;
}
使用的代码没有改变,但无论我编译为 C 还是 C++,它都会改变 Valgrind 基准测试的结果。但是,这些值在编译器之间保持一致。 运行程序的时间分配(峰值)如下:
- GCC (C):1,032 字节 (1 KB)
- G++ (C++):73,744 字节,(~74 KB)
- Clang (C):1,032 字节 (1 KB)
- Clang++ (C++):73,744 字节(~74 KB)
为了编译,我使用了以下命令:
clang -O3 -o c-clang ./main.c
gcc -O3 -o c-gcc ./main.c
clang++ -O3 -o cpp-clang ./main.cpp
g++ -O3 -o cpp-gcc ./main.cpp
对于 Valgrind,我在每个编译器和语言上 运行 valgrind --tool=massif --massif-out-file=m_compiler_lang ./compiler-lang
,然后 ms_print
用于显示峰值。
我是不是做错了什么?
堆使用来自C++标准库。它在启动时分配内存供内部库使用。如果你不 link 反对它,C 和 C++ 版本之间应该有零差异。使用 GCC 和 Clang,您可以使用以下命令编译文件:
g++ -Wl,--as-needed main.cpp
这将指示 linker 不要 link 反对未使用的库。在您的示例代码中,没有使用 C++ 库,因此它不应该 link 针对 C++ 标准库。
您也可以使用 C 文件进行测试。如果你编译:
gcc main.c -lstdc++
堆使用情况将重新出现,即使您已经构建了 C 程序。
堆的使用显然取决于您使用的特定 C++ 库实现。在你的例子中,那是 GNU C++ 库,libstdc++. Other implementations might not allocate the same amount of memory, or they might not allocate any memory at all (at least not on startup.) The LLVM C++ library (libc++) 例如在启动时不进行堆分配,至少在我的 Linux 机器上是这样:
clang++ -stdlib=libc++ main.cpp
堆的使用与完全不link一样。
(如果编译失败,则可能是libc++没有安装,包名一般包含"libc++"或"libcxx"。)
GCC 和 Clang 都不是编译器——它们实际上是工具链驱动程序。这意味着它们调用编译器、汇编器和链接器。
如果您使用 C 或 C++ 编译器编译代码,您将得到相同的程序集。汇编程序将生成相同的对象。不同之处在于,工具链驱动程序将为两种不同的语言提供不同的输入到链接器:不同的启动(C++ 需要代码为在命名空间级别具有静态或 thread-local 存储持续时间的对象执行构造函数和析构函数,并且需要基础结构例如,用于在异常处理期间支持展开的堆栈帧)、C++ 标准库(在名称空间级别也有静态存储持续时间的对象),以及可能的其他运行时库(例如,libgcc 及其 stack-unwinding 基础设施).
简而言之,导致占用空间增加的不是编译器,而是您通过选择 C++ 语言选择使用的内容的链接。
C++ 确实具有 "pay only for what you use" 哲学,但使用该语言需要付出代价。您可以禁用部分语言(RTTI、异常处理),但您不再使用 C++。正如另一个答案中提到的,如果您根本不使用标准库,您可以指示驱动程序将其省略 (--Wl,--as-needed) 但如果您不打算使用任何C++ 或其库的特性,你为什么还要选择 C++ 作为编程语言?