在生产环境中保持可调试性的同时优化构建 C++ 程序的最佳实践

问题描述 投票:0回答:2

我正在编写一个 C++ 服务器程序,将部署到 *nix 系统(Linux/macOS)。程序有时在生产环境中会遇到段错误,我想收集一些信息,例如核心转储文件。但我不知道这样做的最佳实践是什么:

  1. 我想让程序表现最好。
  2. 如果真的发生了,我想离线分析生产环境中的核心转储。

我了解到有些事情我可以尝试:

  1. RelWithDebInfo
    Release
    CMAKE_BUILD_TYPE
    ,但似乎它们有不同的优化级别。所以我认为
    RelWithDebInfo
    构建的性能不如
    Release
    构建。 (根据此处“RelWithDebInfo 使用 -O2,但 Release 使用 -O3” 什么是 CMAKE_BUILD_TYPE:Debug、Release、RelWithDebInfo 和 MinSizeRel?
  2. objectcopy
    /
    strip
    这样的工具允许您从二进制文件中删除调试信息(如何在构建目标之外生成 gcc 调试符号?
  3. 处理
    SIGSEGV
    信号时打印堆栈跟踪(如何在程序崩溃时自动生成堆栈跟踪

我是部署生产C++服务器程序的新手,我想知道以下问题的答案:

  1. 在这种情况下建议使用什么构建类型,
    RelWithDebInfo
    还是
    Release
  2. 与选择不同的构建类型相比,我什么时候需要使用
    strip
    这样的工具?
  3. 如果我为生产部署创建
    Release
    构建二进制文件,当
    Release
    构建在生产环境中生成核心转储时,我可以稍后使用相同版本的源代码来构建
    RelWithDebInfo 
    二进制文件并使用 ( gdb +
    RelWithDebInfo 
    二进制 +
    Release
    构建核心转储)用于核心转储分析?
  4. 在生产环境中打开核心转储是否常见?如果这不是一个好的做法,那么收集信息以进行故障排除、崩溃时打印堆栈跟踪的推荐方法是什么?

总的来说,我想知道如何建议为生产构建 C++ 程序,以便在我仍然能够对其进行故障排除的同时对其进行最佳优化。非常感谢。

c++ deployment cmake stack-trace coredump
2个回答
3
投票

这将是一个相当笼统的答案。

  1. 如果您仍然遇到可靠性问题,请选择
    RelWithDebInfo
    。或者,您可以覆盖
    -O2
    优化,让编译器全程优化。
  2. 当存在调试信息时,您需要
    strip
    。这不会改变任何实际执行的内容,但会删除使调试变得更加容易的内容。您仍然可以调试剥离的可执行文件,但更难理解发生了什么。
  3. 不,由于优化级别不同。如果两者之间唯一的区别是一个被剥夺了而另一个没有被剥夺,那么是的。但不同的优化级别,最终的组装结果实际上会有所不同。
  4. 通常不建议在生产环境中启用核心转储,主要是出于安全原因。例如,核心转储可能包含纯文本密码、会话令牌等。这些都是其他人不应该看到的东西。如果您可以完全控制运行该程序的机器,那么这个问题就会稍微小一些。另一个问题是磁盘空间使用情况。核心转储可能会很大,具体取决于您的程序正在执行的操作。如果你有固定的核心文件名,那么至少不会有超过一个文件,但如果你有一个包含时间戳和/或 PID 的名称,那么你可以有多个文件,每个文件占用很多 - GB 的大小 -的空间。这可能会再次导致问题。

一般规则是(或应该是)您认为发布环境是敌对的。有时这是真的,有时则不然——这里不能适用一般性,因为只有你知道你的具体情况。

我总是部署我的东西完全优化。如果程序特别有问题,我只会包含调试信息,因为这样可以轻松运行它或使用

gdb
附加到它。

全面优化的缺点是有时事情看起来与您编写的代码有点不同。事情的顺序可能会改变,有些事情可能根本不会发生,并且您可能会发现某些函数实际上并不作为正确的独立函数存在,因为编译器认为内联它们会更好。这些是我观察到的变化,但可能还有其他变化。


0
投票

最近我了解到有像Google Breakpad这样的工具可以生成小型转储格式的崩溃报告,可以在生产环境中收集和分析。我还没有尝试过,但它对于这个确切的目的可能很有用。

Breakpad

© www.soinside.com 2019 - 2024. All rights reserved.