【问题标题】:What are the negative consequences of including and/or linking things that aren't used by your binary?包含和/或链接二进制文件未使用的内容有什么负面影响?
【发布时间】:2010-10-19 14:43:54
【问题描述】:

假设我有一个正在构建的二进制文件,并且我包含了一堆从未实际使用过的文件,并且后续是否链接到这些包含文件所描述的库? (同样,这些库从未使用过)

除了增加编译时间之外,这样做的负面后果是什么?

【问题讨论】:

    标签: c++ linux linker g++ ld


    【解决方案1】:

    我能想到的几个是命名空间污染二进制大小

    【讨论】:

    • 真的会增加二进制大小吗?对于动态链接库,我认为不会。
    • 确实不会,虽然命名空间污染是地狱
    • 静态链接怎么样?
    • 智能链接器是否只是跳过链接未引用的库?我记得来自 VC++ 的“opt ref”消息??
    • 如果没有调用函数,则没有对函数的引用,因此无论库是动态的还是静态的,都不会增加大小。至于命名空间污染,这正是引入 C++ 命名空间来控制的,所以也没有问题。
    【解决方案2】:

    除了 Sasha 列出的内容之外,还有维护成本。当您选择删除未使用的东西时,您是否能够轻松检测到哪些是已使用的,哪些是未使用的?

    【讨论】:

      【解决方案3】:

      除了编译时间;复杂性增加,调试时不必要的分心,维护开销。

      除此之外,什么都没有。

      【讨论】:

        【解决方案4】:

        如果这些库从未使用过,则可执行文件的大小不会增加。

        【讨论】:

        • +1,链接器没有理由添加未在任何地方引用的目标文件。
        • 但前提是链接器可以保证对象不被另一个编译单元/库引用。现在,链接器确实会从静态链接库中删除未明确使用的对象(因此链接顺序很重要),但不会从主可执行文件主体中删除。
        • UNIX 链接器的链接顺序通常很重要,您可能必须多次精确链接同一个库,因为它们(太!)擅长删除未引用的符号
        • +1。依赖检查是“库”与仅仅是一个巨大的目标文件的区别。
        【解决方案5】:

        根据具体的链接器,您可能还会注意到未使用库的全局对象仍会被构造。这意味着内存开销并增加了启动成本。

        【讨论】:

        • +1,很有趣。 C++ 标准对此有立场吗?
        • 是的,“在第一次调用定义全局的 .cpp 中的函数之前进行初始化”。 “库加载时”就是这样一个时刻,而且很容易检测到。
        • 啊,谢谢。是的,据此,(a)根本不构造它是合法的,因为不会调用该源文件中的任何函数;或 (b) 随时建造。呸:(
        【解决方案6】:

        我在链接 .lib 文件时从未遇到任何问题,该文件只使用了其中的一小部分。只有真正使用的代码才会链接到可执行文件中,链接时间并没有明显增加(使用 Visual Studio)。

        【讨论】:

          【解决方案7】:

          如果您链接到二进制文件并且它们在运行时加载,它们可能会执行非平凡的初始化,这可以做任何事情,从分配少量内存到消耗稀缺资源,以您不知道的方式改变模块的状态期待,甚至超越。

          你最好去掉你不需要的东西,只是为了消除一堆未知数。

          【讨论】:

            【解决方案8】:

            如果您包含但未使用的库不在目标系统上,即使没有必要,它也无法编译。

            【讨论】:

              【解决方案9】:

              Here 是我对有关 C 和静态库的类似问题的回答。也许它在 C++ 上下文中也对您有用。

              【讨论】:

                【解决方案10】:

                您提到了编译时间的增加。据我了解,这些库是静态链接的,而不是动态链接的。在这种情况下,这取决于链接器如何处理未使用的函数。如果它忽略它们,您将主要遇到维护问题。如果它们被包括在内,可执行文件的大小将会增加。现在,这比它在硬盘上占据的位置更重要。由于缓存问题,大型可执行文件可能会运行得更慢。如果exe中的活动代码和非活动代码相邻,它们将被缓存在一起,从而使缓存实际上更小,效率更低。

                VC2005 及更高版本有一个称为 PGO 的优化,它以确保有效缓存常用代码的方式对可执行文件中的代码进行排序。我不知道 g++ 是否有类似的优化,但值得研究一下。

                【讨论】:

                  【解决方案11】:

                  这里对问题进行了一点汇编,必要时进行维基编辑:

                  主要问题似乎是:命名空间污染 这可能会导致未来的调试、版本控制出现问题,并增加未来的维护成本。

                  至少会有轻微的二进制膨胀,因为函数/类/命名空间引用将被维护(在符号表中?)。动态库不应该大大增加二进制文件的大小(但它们会成为二进制文件运行的依赖项?)。从 GNU C 编译器来看,如果源代码中从未引用静态链接库,则不应将其包含在最终二进制文件中。 (基于 C 编译器的假设,可能需要澄清/纠正)

                  此外,根据您的库的性质,可能会实例化全局和静态对象/变量,从而导致增加启动时间和内存开销

                  哦,增加了编译/链接时间。

                  【讨论】:

                    【解决方案12】:

                    当我在源代码树中编辑文件时,我觉得很沮丧,因为我正在处理的某些符号出现在源文件中(例如,我刚刚更改了原型的函数名称 - 或者,可悲但更多通常,只是将原型添加到标题中)所以我需要检查使用是否正确,或者编译器现在告诉我该文件中的使用不正确。所以,我编辑文件。然后我看到一个问题——这个文件在做什么?事实证明,虽然代码在产品中被“使用”了,但它实际上并没有被积极使用。

                    我在星期一发现了这个问题。一个包含 10,000 多行代码的文件调用了一个函数“extern void add_remainder(void);”参数为 0。所以,我去修复它。然后我查看了其余的代码......原来它是大约 15 年前的一个开发存根,从未被删除。结果证明,干净地删除代码涉及对六个以上文件的微小编辑——而且我还没有弄清楚从枚举中间删除枚举常量是否安全,以防万一。暂时标记为“未使用/已过时 - 可以安全移除吗?”。

                    在过去的 15 年中,该代码块的覆盖率为零 - 生产、测试​​......的确,它只是庞大系统的一小部分 - 从百分比来看,它不到 1%图表。不过,这是额外浪费的代码。

                    令人费解。恼人的。令人沮丧的普遍(到目前为止,我已经记录并修复了至少六个类似的错误)。

                    浪费了我的时间 - 以及其他开发人员的时间。多年来,其他人在做我正在做的事情时定期编辑该文件 - 一项彻底的工作。

                    【讨论】:

                    • +1。总而言之:“更多代码 => 更多维护。”根据我的经验,维护时间随着代码库大小的增加而呈线性增长。
                    • 我同意这种分析。这使得我使用的软件以及 MS Windows 等软件极难维护!
                    【解决方案13】:

                    如果构建树没有得到很好的维护,它甚至可能无法编译。如果您在没有交换空间的嵌入式系统上编译。编译器在尝试编译大型目标文件时可能会耗尽内存。

                    这件事最近发生在我们身上。

                    【讨论】:

                      猜你喜欢
                      • 1970-01-01
                      • 2010-09-06
                      • 2012-12-13
                      • 2011-07-28
                      • 2010-09-24
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      相关资源
                      最近更新 更多