未使用代码中的开销

12

我想知道在代码中有未使用的函数会带来多大的开销。

比如说,你有一些调试日志记录,然后你给大多数对象都添加了一个ToString()函数,在调试日志中使用它。

在发布版本中,这个调试日志将不再被使用。此时是否值得移除那些ToString()函数的源代码?(例如通过宏)

还是说它们只会使可执行文件稍微变大,否则不会影响性能?例如没有速度上的影响?或者编译器或链接器甚至会删除那些未被使用的函数吗?如果编译器或链接器不删除代码,那如果ToString()函数被定义为内联函数呢?它会尝试将代码内联,而由于该函数从未被调用过,所以代码会消失吗?

我想每个函数都需要在静态库中保留,但一旦编译成可执行文件,肯定会有很多东西被链接器忽略掉吧?

另外一个问题,如果编译器选择不内联一个内联函数,以至于该内联函数在几个编译单元中都被定义为函数,那么链接器会丢弃多余的定义,只在最终连接时链接一个吗?

谢谢


1
这可能取决于编译器以及它使用的优化方式。 - soandos
4
“过早优化是万恶之源” - 唐纳德·科斯塔(Donald Knuth) - Maurits Rijk
9
我厌倦了过早优化的口号。谢谢你的帮助。另外,“了解你正在做的事情可能有助于你做好它。”你同意吗?当然,理解编译器和链接器并不是坏事。但还是感谢你的建议。 - Cookie
5
@Maurits: 我不喜欢不完整的引用。在此之前不要忘记加上“说97%的时间”。 - Matthieu M.
1
完整的引用似乎是:“我们应该忘记小效率,大约97%的时间:过早优化是万恶之源”。 - Maurits Rijk
显示剩余2条评论
4个回答

5
这取决于编译器和优化级别。G++和MSVC++会删除未使用的内联函数,但保留未使用的非内联函数。例如,在普通程序中仅使用STL的一小部分,所有未使用的函数都将被删除,因为它们被定义为内联函数。另一方面,GCC保留所有函数,即使是未使用的内联函数。回答您的另一个问题:如果某个函数在多个编译单元中有定义,则链接器会出错并拒绝链接,除非该函数被定义为内联函数。

就你最后一句话而言:除非它被定义为内联。这样做应该可以防止编译器皱眉,即使如果没有定义内联,编译器也会皱眉。 - Cookie

3

1. 关于编译器和链接器

这取决于您如何创建可执行文件。

通常,可执行文件会被剥离未使用的内容。因此,如果您静态链接(并且使用了正确的优化选项),函数将被删除。

但是,如果您动态链接,它们将存在,因为就库而言,它们被导出并因此被使用。

至于多个定义,这取决于符号是否弱。如果是弱的,则链接器选择其中一个定义,否则它会出错。

最后,它们可能只代表程序的一小部分。

2. 如何解决这个问题?

这是一个难题,您可以使用预处理器来删除一些内容,但是代码中充斥着预处理指令真的很烦人。

就我个人而言,我不会费心去做这件事......特别是因为我也在发布版中记录日志(否则如何追踪生产问题?)。

一个解决方案是在单独的文件中定义有问题的函数,并在发布版中不进行链接。注意:我认为对于虚函数,这种方法行不通,因为它们至少在vtable中被使用。


2
链接器会删除重复的函数和未被引用的数据(Microsoft链接器提供/OPF:REF/OPT:ICF开关来调整这些设置)。在大多数情况下,链接器是否能够很好地丢弃不需要或冗余的内容并不重要-与生成大量代码(例如使用STL或其他模板库)相比,一些小函数对可执行文件大小的影响是微不足道的。然而,如果您需要使可执行文件尽可能小(或者如果您发现您的调试代码实际上占据了大部分映像大小),则使用#ifdef来排除特定函数是最简单的方法。虽然这样使得代码有点难看懂,但优点是您不能意外忽略发布版本中的少数调试代码,因为任何尝试调用不存在的函数都将导致编译错误。另一个#ifdef的优点是它是可移植的,并且不依赖于特定的编译器系统 :-/

那么你会说将这样的调试 tostring 函数定义为内联函数更可取吗? - Cookie
2
由于编译器始终可以选择是否内联函数,我倾向于只在一个目的上使用“inline”:能够在共享头文件中具有函数定义。由于这对于在类体中定义的成员函数是隐式的,因此我不会指定“inline”。但请注意,这仅是我的个人方法。 - Alexander Gessler

0
如果您将非虚函数放在库中的单独文件中,并进行静态链接,则只有在使用时才会将其添加到可执行文件中。但实际上唯一的区别在于可执行文件的大小;这可能会影响局部性和性能,但我很惊讶它是否真正会在实践中产生实质性的差异。因此,通常情况下,我认为这种技术在应用程序中不值得麻烦。(另一方面,如果您正在提供第三方库,则绝对需要将每个非虚函数放在单独的文件中。)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接