为什么 C++ 什么都不做时比 C 慢
Why is C++ slower than C when doing literaly nothing
C++ 在什么都不做时比 C 慢将近 4 倍(至少在我的机器上是这样)。以下文件用 g++ 编译时,比用 gcc 慢 4 倍:
int main() {}
对于 time sh -c 'for i in $(seq 0 1000) ; do ./a.out ; done'
,我得到 C 版本的 0.515s,C++ 版本的 2s。这是为什么?
这个程序什么都没有做,两个版本的反汇编程序基本相同,为什么C++版本慢了大约4倍?
我的猜测是 C++ 库需要更长的时间来加载,但程序集是如此相似,我想不出 C++ 这么慢的原因。
编辑:好吧,看来我只是部分反汇编了程序(objdump -d
而不是 objdump -D
),导致我看不到正在加载的库。现在看到反汇编的输出非常明显,C++ 版本只是需要更长的时间来加载它的库。我首先所说的“略有不同”的意思是 mov
或 call
中使用的地址在没有调用其他函数的情况下发生了分歧(如果我正确理解 objdump
输出的含义)。
所以主要问题已经解决了,但是对于一个什么都不做的程序来说,2 秒是巨大的。如果有帮助,我正在使用 x86_64 处理器,并且我构建了可执行文件 gcc empty.c
和 g++ empty.cpp
。我认为问题确实出在我使用 HDD,因此需要更多时间来加载 libstd++
。我还使用 -static
标志构建,现在得到非常相似的结果(0.246s 和 0.241s)。 C 二进制文件也与 C++ 二进制文件完全相同(如果那不是 diff
错误)。
C++ standard library初始启动比C运行时重。
C++ ABI needs to initialize some structures for basic language features. Mutex locks for thread-safe initialization of data, exeptions, thread local storage, RTTI等
这就是为什么使用 C++ 编译器创建的空可执行文件启动速度比空 C 程序慢的原因。同样,使用汇编语言创建的空程序的启动速度要比使用 C 使用 full-featured C 运行时(CRT、GNU LIBC 等)创建的类似程序快得多。
事实上,你什么都不比较,因为你的程序什么都不做。你得到的不是程序执行时间,在你的情况下它是空的,而是进程执行时间,即加载+运行 +terminate,如果您的程序需要更多资源,它会更长。
一些数字可以对此有所启发:
假设我们有 emptyc
和 emptycpp
,分别用 gcc-10.3 和 g++-10.3
编译
在我的系统上:
emptyc
:
- 文件大小:13232
- elf 动态部分:17 个条目(1 个共享库)
- truss 系统调用报告:48 个系统调用,包括 6 个打开和 11 个 mmap
emptycpp
- 文件大小:13312
- elf 动态部分:20 个条目(4 个共享库)
- truss 系统调用报告:88 个系统调用,包括 15 个打开和 29 个 mmap
结论:
用 g++ 编译的程序比用 gcc 编译的相同程序需要更多的资源。
生成 88 个系统调用的进程可能比生成 48 个系统调用的进程慢。
C++ 在什么都不做时比 C 慢将近 4 倍(至少在我的机器上是这样)。以下文件用 g++ 编译时,比用 gcc 慢 4 倍:
int main() {}
对于 time sh -c 'for i in $(seq 0 1000) ; do ./a.out ; done'
,我得到 C 版本的 0.515s,C++ 版本的 2s。这是为什么?
这个程序什么都没有做,两个版本的反汇编程序基本相同,为什么C++版本慢了大约4倍?
我的猜测是 C++ 库需要更长的时间来加载,但程序集是如此相似,我想不出 C++ 这么慢的原因。
编辑:好吧,看来我只是部分反汇编了程序(objdump -d
而不是 objdump -D
),导致我看不到正在加载的库。现在看到反汇编的输出非常明显,C++ 版本只是需要更长的时间来加载它的库。我首先所说的“略有不同”的意思是 mov
或 call
中使用的地址在没有调用其他函数的情况下发生了分歧(如果我正确理解 objdump
输出的含义)。
所以主要问题已经解决了,但是对于一个什么都不做的程序来说,2 秒是巨大的。如果有帮助,我正在使用 x86_64 处理器,并且我构建了可执行文件 gcc empty.c
和 g++ empty.cpp
。我认为问题确实出在我使用 HDD,因此需要更多时间来加载 libstd++
。我还使用 -static
标志构建,现在得到非常相似的结果(0.246s 和 0.241s)。 C 二进制文件也与 C++ 二进制文件完全相同(如果那不是 diff
错误)。
C++ standard library初始启动比C运行时重。
C++ ABI needs to initialize some structures for basic language features. Mutex locks for thread-safe initialization of data, exeptions, thread local storage, RTTI等
这就是为什么使用 C++ 编译器创建的空可执行文件启动速度比空 C 程序慢的原因。同样,使用汇编语言创建的空程序的启动速度要比使用 C 使用 full-featured C 运行时(CRT、GNU LIBC 等)创建的类似程序快得多。
事实上,你什么都不比较,因为你的程序什么都不做。你得到的不是程序执行时间,在你的情况下它是空的,而是进程执行时间,即加载+运行 +terminate,如果您的程序需要更多资源,它会更长。
一些数字可以对此有所启发:
假设我们有 emptyc
和 emptycpp
,分别用 gcc-10.3 和 g++-10.3
在我的系统上:
emptyc
:- 文件大小:13232
- elf 动态部分:17 个条目(1 个共享库)
- truss 系统调用报告:48 个系统调用,包括 6 个打开和 11 个 mmap
emptycpp
- 文件大小:13312
- elf 动态部分:20 个条目(4 个共享库)
- truss 系统调用报告:88 个系统调用,包括 15 个打开和 29 个 mmap
结论:
用 g++ 编译的程序比用 gcc 编译的相同程序需要更多的资源。 生成 88 个系统调用的进程可能比生成 48 个系统调用的进程慢。