发布生成 .pdb 文件,为啥?

Posted

技术标签:

【中文标题】发布生成 .pdb 文件,为啥?【英文标题】:Release generating .pdb files, why?发布生成 .pdb 文件,为什么? 【发布时间】:2011-07-24 08:19:52 【问题描述】:

为什么 Visual Studio 2005 在发布时编译时会生成 .pdb 文件?我不会调试发布版本,为什么会生成它们?

【问题讨论】:

为什么要在realease中生成pdb?因此,当崩溃报告从野外传来时,您就有了调试它的信息。另一个价值是客户可以在原作者不调试的情况下调试它。 @IanBoyd:该评论的第二句话暗示,您部署了 PDB。这在绝大多数情况下是不可取的。 @IInspectable 或is desirable @IanBoyd:绝大多数情况不包括操作系统部署。此外,这些 PDB 不包含私有符号,在您生成 PDB 时默认包含这些符号。 @IanBoyd:“但是本地代码编译器仍然没有简单的方法来支持现场调试。” - 顺便说一句,他们可以。例如,作为 WER 的一部分或在任意时间使用任务管理器提取 minidump,并让供应商对其进行分析。这不需要运送 PDB。有关信息,请参阅Crash Dump Analysis。 【参考方案1】:

因为没有 PDB 文件,除了地址级调试之外,不可能调试“发布”版本。优化确实对您的代码有很大影响,因此很难如果出现问题(例如,抛出异常),请找出罪魁祸首。即使设置断点也非常困难,因为源代码行无法与生成的汇编代码一对一匹配(甚至与生成的汇编代码的顺序相同)。 PDB 文件可以帮助您和调试器,使事后调试变得更加容易。

您指出,如果您的软件已准备好发布,那么您应该在那时完成所有调试。虽然这确实是真的,但有几点需要牢记:

    您应该使用“发布”版本测试和调试您的应用程序(在发布之前)。这是因为打开优化(在“调试”配置下默认禁用)有时会导致出现您无法捕捉到的细微错误。进行此调试时,您需要 PDB 符号。

    客户经常报告仅在“理想”条件下出现的边缘情况和错误。这些东西几乎不可能在实验室中重现,因为它们依赖于用户机器的一些古怪配置。如果他们是特别有帮助的客户,他们会报告引发的异常并为您提供堆栈跟踪。或者他们甚至会让你借用他们的机器来远程调试你的软件。在任何一种情况下,您都需要 PDB 文件为您提供帮助。

    应该始终在启用优化的“发布”版本上进行分析。 PDB 文件再次派上用场,因为它们允许将被分析的汇编指令映射回您实际编写的源代码。

您无法在编译后返回并生成 PDB 文件。* 如果您在构建过程中不创建它们,您就失去了机会.创建它们并没有什么坏处。如果你不想分发它们,你可以简单地从你的二进制文件中省略它们。但是,如果您后来决定要它们,那您就不走运了。 最好始终生成它们并存档一份副本,以备不时之需。

如果您真的想关闭它们,这始终是一种选择。在项目的“属性”窗口中,将“Debug Info”选项设置为“none”,以便更改任何要更改的配置。

但请注意,“调试”和“发布”配置执行默认情况下使用不同的设置来发出调试信息。您将希望保留此设置。 Debug 版本的“Debug Info”选项设置为“full”,这意味着除了 PDB 文件之外,调试符号信息也嵌入到程序集中。您还可以获得支持编辑并继续等酷炫功能的符号。在 Release 模式下,选择了“pdb-only”选项,就像听起来一样,它只包含 PDB 文件,而不影响程序集的内容。所以它并不像/bin 目录中存在或不存在 PDB 文件那么简单。但假设您使用“pdb-only”选项,PDB 文件的存在绝不会影响代码的运行时性能。

* 作为Marc Sherman points out in a comment,只要你的源代码没有改变(或者你可以从版本控制系统中检索原始代码),你可以重建它并生成匹配的 PDB 文件。至少,通常情况下。这在大多数情况下都很好用,但the compiler is not guaranteed to generate identical binaries each time you compile the same code,所以可能会有细微的差别。更糟糕的是,如果您同时对工具链进行了任何升级(例如为 Visual Studio 应用服务包),则 PDB 匹配的可能性更小。为了保证可靠地生成 ex postfacto PDB 文件,您不仅需要存档版本控制系统中的源代码,还需要存档整个构建工具链的二进制文件,以确保您可以精确地重新创建构建环境的配置。不用说,简单地创建和归档 PDB 文件要容易得多。

【讨论】:

"编译后无法生成 PDB 文件。" - 如果您的源代码没有更改,那么您可以在事后重建以生成可用的 PDB。默认情况下,windbg 不会加载此 PDB,但您可以通过指定 /i 选项(如 .reload /i foo.dll)来强制加载它。即使 foo.pdb 是在释放 foo.dll 后创建的,它也会加载 foo.pdb。 我注意到每个新编译都有不同的哈希摘要,因此即使在相同的环境中,每个构建也会有细微的差异。 PDB 的地址是否不会随变化而变化,因此需要保持 PDB 不受该构建的影响?只是将其作为一个想法提出,因为我并不真正了解 PDB 是如何工作的,或者为什么哈希在构建之间会发生变化。 @the 在脚注中,我链接到an article 解释说“C# 编译器在设计上不会两次生成相同的二进制文件。C# 编译器在每个程序集中嵌入一个新生成的 GUID,每次运行它,从而确保没有两个程序集是逐位相同的。” 这解释了为什么它具有不同的哈希,因此具有不同的 PDB 文件。这可以通过十六进制编辑器修复,但对用户不友好。而且也超出了这个答案的范围。 Roslyn 中有一个新功能,称为确定性构建。 “当给定相同的输入时,/deterministic 标志会导致编译器逐字节发出完全相同的 EXE / DLL。”这意味着最初使用此标志编译的项目可以重新编译为完全相同的二进制文件,只要您正在编译的代码是相同的。更详细的解释可以在Deterministic builds in Roslyn 找到 我从来没有发现 pdbs 的发布版本有任何用处【参考方案2】:

可以为ReleaseDebug 生成PDB。这是设置在(在 VS2010 中但在 VS2005 中必须类似):

项目 → 属性 → 构建 → 高级 → 调试信息

只需将其更改为None

【讨论】:

但是你为什么要这样做呢?如果您的软件已准备好发布,那么您应该已经完成​​了所有的调试 因为您可以调试生产问题。一旦我们不得不这样做。 将 PDB 标题用于生产代码的优点是 .NET 在抛出异常时将使用这些文件。它生成带有文件名和行号的堆栈跟踪,这通常非常方便! @m.edmondson:是的,没错。您仍会被告知抛出的异常(如FileNotFoundException),但您将看不到堆栈跟踪。这使得很难准确确定是哪代码导致了异常被抛出。 @m.edmondson 只是补充一点,如果您正在寻找一种工具来远程调试生产框中的一个问题,那么 Windows SDK 附带了一个非常著名的工具,称为 WinDbg,它支持远程调试。请查看下面提到的链接。希望这可以帮助! msdn.microsoft.com/en-in/library/windows/hardware/…【参考方案3】:

如果没有 .pdb 文件,几乎不可能单步执行生产代码;您必须依赖其他可能既昂贵又耗时的工具。 我知道您可以使用跟踪或 windbg ,但这实际上取决于您想要实现的目标。 在某些情况下,您只想使用生产数据单步执行远程代码(没有错误或异常)以观察特定行为,这就是 .pdb 文件派上用场的地方。没有他们在该代码上运行调试器是不可能的。

【讨论】:

【参考方案4】:

为什么你如此确定你不会调试发布版本?有时(希望很少,但会发生)您可能会从客户那里得到一份缺陷报告,由于某种原因(不同的时间、小的不同行为或其他原因)在调试版本中不可重现。如果该问题在发布版本中似乎可以重现,您将很高兴拥有匹配的 pdb。

【讨论】:

@m.edmondson 使用 RDP、Webex 等访问远程机器并在那里安装 windbg。设置你的符号路径和 bam,你是金子! 更详细指南的链接会更有帮助。这个单行的方法可能会导致人们(比如我自己)走上错误的道路。例如,大多数 .NET 开发人员对 Windbg 一无所知。 @m.edmondson - Visual Studio 的某些版本能够执行远程调试。从调试菜单中,您可以在远程计算机上“附加到进程”。 远程调试生产应用程序实例是个好主意吗?它不会破坏线程的并行执行并强制它们在调试时串行运行吗?【参考方案5】:

此外,您还可以利用故障转储来调试您的软件。客户将其发送给您,然后您可以使用它来识别源代码的确切版本 - Visual Studio 甚至会使用故障转储提取正确的调试符号集(如果设置正确,还可以提取源代码)。请参阅 Microsoft 的 documentation on Symbol Stores。

【讨论】:

【参考方案6】:

.PDB 文件是“程序数据库”的简称。它包含有关调试器的调试点和使用或引用的资源的信息。它是在我们构建为调试模式时生成的。它允许应用程序在运行时进行调试。

大小是在调试模式下增加.PDB 文件。它在我们测试应用程序时使用。

pdb 文件的好文章。

http://www.codeproject.com/Articles/37456/How-To-Inspect-the-Content-of-a-Program-Database-P

【讨论】:

“发布或部署时不需要此文件”除非有人在该发布版本中遇到崩溃,并且您从他们那里获得的崩溃报告不包含可用的堆栈跟踪......然后毕竟你会希望你把它包括在内。 不正确。如果没有 .pdb 文件,您将获得完整的堆栈跟踪,但没有源文件名。您可以在收到崩溃报告后在内部恢复它。如果您关心自己的知识产权并混淆源代码,则必须保存 .pdb 文件,但不要部署它们。【参考方案7】:

在多项目解决方案中,您通常希望有一个根本不生成 PDB 或 XML 文件的配置。与其将每个项目的Debug Info 属性更改为none,不如添加一个仅适用于特定配置的构建后事件会更方便。

不幸的是,Visual Studio 不允许您为不同的配置指定不同的构建后事件。所以我决定手动执行此操作,通过编辑启动项目的csproj 文件并添加以下内容(而不是任何现有的PostBuildEvent 标签):

  <PropertyGroup Condition="'$(Configuration)' == 'Publish'">
    <PostBuildEvent>
        del *.pdb
        del *.xml
    </PostBuildEvent>
  </PropertyGroup>

不幸的是,这将使构建后事件文本框变为空白,并且将任何内容放入其中可能会产生不可预知的结果。

【讨论】:

这将删除所有*.xml文件,请小心。【参考方案8】:

调试符号 (.pdb) 和 XML 文档 (.xml) 文件占总大小的很大一部分,不应成为常规部署包的一部分。 但是应该可以在需要时访问它们。

一种可能的方法:在 TFS 构建过程结束时,将它们移动到单独的工件中。

【讨论】:

【参考方案9】:

实际上,如果没有 PDB 文件和他们拥有的符号信息,就不可能创建成功的崩溃报告(内存转储文件),而且 Microsoft 也无法完整了解导致问题的原因。

因此,拥有 PDB 可以改进崩溃报告。

【讨论】:

但是如果没有 .pdb 文件会丢失什么? 编译后无法生成PDB文件。所以软件major.minor[.build[.revision]]的每个版本都应该保存在微软,以便正确理解发生了什么,但这还不是全部。 不保证每次编译相同代码时编译器都会生成相同的二进制文件。 问题是崩溃报告中将缺少什么以及崩溃报告将如何受到影响。 .NET pdb 文件仅包含私有变量名称和源文件名称。其他所有内容(方法名称、签名等)都将在元数据信息的堆栈跟踪中。 没有 PDB 文件也包含非私有数据:github.com/microsoft/microsoft-pdb.

以上是关于发布生成 .pdb 文件,为啥?的主要内容,如果未能解决你的问题,请参考以下文章

使用 linux 和 g++ 生成 pdb 文件

VS中Release模式下生成去掉生成pdb文件

使用mingw构建库时如何生成pdb文件?

VSVS调试mimikatz-生成PDB文件

使用 Visual Studio 2013 为本机 DLL 正确生成 PDB 文件

VS中Release模式下生成去掉生成pdb文件