未使用代码中的开销
Overhead in unused code
我想知道在代码中使用未使用的函数会带来什么开销。
例如,假设您有一些调试日志,然后为大多数对象提供调试日志中使用的ToString()函数。
在未使用调试日志记录的发布版本中。那么,删除那些ToString()函数的源代码值得吗?(例如通过Macro?)
或者它们只是使可执行文件稍微大一点,否则不会影响性能?例如没有速度影响?或者编译器或链接器是否可能在不使用函数的情况下删除这些函数?如果编译器或链接器没有删除代码,那么如果ToString()函数是内联定义的呢?大概它会尝试内联代码,但由于函数从未被调用,它会消失吗?
我想每个函数都需要保留在静态库中,但一旦编译成可执行文件,肯定会有很多东西被链接器忽略?
另一个大致相似的注意事项是,如果编译器选择不内联内联函数,从而将内联函数定义为几个编译单元中的函数,那么链接器会丢弃多余的定义,并在最后只链接其中一个吗?
感谢
这取决于编译器,我想还取决于优化级别。
G++和MSVC++删除未使用的内联函数,但保留未使用的非内联函数。例如,在普通程序中只使用STL的一小部分。所有未使用的函数都会被删除,因为它们被定义为内联函数。
另一方面,GCC保留所有函数,甚至是未使用的内联函数。
回答你的另一个问题:如果一个函数以某种方式定义在多个编译单元中,链接器会皱眉头拒绝链接,除非它被定义为内联。
1。关于编译器和链接器
这实际上取决于您如何创建可执行文件。
通常,可执行文件会被剥离掉任何未使用的内容。因此,如果静态链接(并使用正确的优化选项),则函数将被删除。
但是,如果您动态链接,它们就会在那里,因为就库而言,它们是导出的,因此会被使用。
至于多重定义,则取决于符号是否弱。如果它很弱,链接器会选择其中一个定义,否则就会阻塞它
最后,它们可能只代表程序的一个边缘部分。
2.如何解决问题
这是一个难题,你总是可以使用预处理器来删除一些东西,但充斥着预处理器指令的代码读起来真的很烦人。
就我个人而言,我不会打扰。。。尤其是因为我也登录了Release(否则如何跟踪生产问题?)。
解决方案可以是在一个单独的文件中定义有问题的函数,而不是在Release中链接它们注意:我认为它不适用于虚拟函数,因为它们至少在vtable
链接器确实删除了重复的函数,也删除了未引用的数据(Microsoft链接器提供了/OPF:REF
和/OPT:ICF
开关来调整这些设置)。
你肯定是对的,在大多数情况下,链接器是否能很好地删除不需要或多余的东西并不重要——对一些小函数的可执行文件大小的影响(与广泛使用STL或其他模板库时生成的代码量相比)是最小的。
也就是说,如果你需要你的可执行文件尽可能小(或者如果你发现你的调试代码真的占用了大部分图像大小),那么#ifdef
ing一切是强制不包含某些函数的最简单方法。它使代码读起来有点难看,但它的优点是,您不会在发布版本中意外错过调试代码的几个位置,因为任何调用不存在的函数的尝试都会导致编译器错误。
#ifdef
的另一个优点是它是可移植的,不依赖于特定的编译器系统:-/
如果将非虚拟函数放在库中的单独文件中,并且静态链接,只有当它是习惯于但唯一真正的区别在于可执行;这可能会影响当地,因此表现,但如果它真的有什么不同,我会感到非常惊讶在实践中。一般来说,我认为这种技术不值得在应用程序中遇到麻烦。(如果您提供的是第三方库,另一方面,您肯定希望单独的文件。)
- C++我的数学有什么问题,为什么我的代码不能正确循环
- 代码在main()中运行,但在函数中出现错误
- 在VS代码中交叉编译Windows与Linux上的MinGW的SDL程序
- 编译包含字符串的代码时遇到问题
- 我在c++代码中生成了一个运行时#3异常
- 如何在linux终端中同时编译和运行c++代码
- 为cl.exe(Visual Studio代码)指定命令行C++版本
- 在Linux for Windows上编译C++代码时出错
- 我的字符计数代码计算错误.为什么
- 孤立代码块在结构中引发异常
- 在编译C++代码(具有dlib和opencv)到WASM时面临问题
- 为什么我的C#代码在调用回C++COM直到Task时会暂停.等待/线程.加入
- 实现无开销push_back的最佳方法是什么
- 处理小于cpu数据总线的数据类型.(c++转换为机器代码)
- 此代码是否违反一个定义规则
- 为什么我的代码在输出中增加了93天
- 如何组织耗时的代码以避免开销
- 在优化和定时的c++代码中从函数中获取数据所带来的难以解释的开销
- OpenMP代码远慢于串行内存或线程开销瓶颈
- 未使用代码中的开销