第 3.3 部分 - 调试器、核心转储和收集核心转储

适用于: .NET Core 2.1、.NET Core 3.1、.NET 5

本文介绍调试器和核心转储以及用于捕获和分析 Linux 中核心转储文件的工具。

先决条件

与前面的部分一样,本部分的结构更加强调开始故障排除时要遵循的理论和原则。 它没有任何先决条件。 但是,如果已按照此培训的所有步骤操作,则应已设置以下各项:

  • Nginx 有两个网站:
    • 第一个网站使用 myfirstwebsite 主机标头(http://myfirstwebsite)侦听请求,并将请求路由到正在侦听端口 5000 的演示 ASP.NET Core 应用程序。
    • 第二个网站使用 buggyambhttp://buggyamb) 主机标头侦听请求,并将请求路由到正在侦听端口 5001 的第二个 ASP.NET Core 示例 buggy 应用程序。
  • ASP.NET Core 应用程序都作为服务运行,这些服务在重新启动服务器时自动重启,或者应用程序停止响应或失败。
  • Linux 本地防火墙已启用并配置为允许 SSH 和 HTTP 流量。

本部分的目标

本部分介绍核心转储和调试器的概念,以及可用于捕获和分析核心转储文件的工具。 本部分介绍的大多数技术和工具将在下一个故障排除实验室中使用。

核心转储

就像 Windows 中的用户模式内存转储一样, 核心转储 是进程的内存快照。 经常需要核心转储来排查 Linux 中的性能问题。

核心转储可由调试器(手动转储收集)按需生成,也可以配置为在进程失败后自动收集。

在 Linux 中进程失败时会发生什么情况?

默认情况下,大多数 Linux 系统都启用了核心转储。 系统为意外终止的任何进程生成核心转储。 这类似于Windows 错误报告(WER)为异常终止的进程生成转储的方式。

下面是 Linux 系统与核心转储文件生成相关的一些关键方面:

  • 默认情况下,当进程意外终止时,将生成核心转储文件。
  • 核心转储文件名为“core”,在当前工作目录或 /var/lib/systemd/coredump 目录中创建。
  • 尽管默认行为是让操作系统生成核心转储文件,但此设置可以覆盖 /proc/sys/kernel/core_pattern ,以便将核心转储文件输出直接传递给另一个应用程序。

可以在配置文件中设置这些默认设置和其他一些设置,例如大小限制。 以下资源更深入地介绍此主题:

Apport:Ubuntu 管理核心转储的方法

在 Ubuntu 中 ,apport 系统服务管理核心转储生成。 即使操作系统的核心转储生成已禁用,Apport 仍将创建核心转储文件。

Apport 用于 /proc/sys/kernel/core_pattern 将核心转储文件直接通过管道传输到 apport 中。 如果在 apport 运行时运行 cat /proc/sys/kernel/core_pattern 命令,应会看到以下结果。

cat core 命令的屏幕截图。

如果禁用 apport,则不会在进程终止时阻止核心转储生成。 相反,它只是停止分配。 然后,系统会生成核心转储本身,从而恢复到其默认行为。 如果在停止 apport 后运行相同 cat /proc/sys/kernel/core_pattern ,你将看到以下默认系统行为。

sudo 和 cat 命令的屏幕截图。

禁用自动核心转储生成

若要禁用自动核心转储文件生成,请执行以下步骤:

  1. 停止和禁用 apport。
  2. 禁用系统的默认操作。

可以停止并禁用与任何其他服务相同的 Apport。 sudo systemctl stop apport使用命令和sudo systemctl disable apport命令停止服务,然后禁用它以防止它重新启动。

sudo systemctl stop apport 命令的屏幕截图。

若要为计算机上所有用户帐户下运行的所有进程禁用操作系统的自动转储文件生成,必须执行以下文章中提供的步骤。

捕获核心转储和调试器

可以使用多种工具捕获核心转储文件,例如 gcore、gdb 和多个工具来分析核心转储文件,例如 objdump、kdumpgdb 和 lldb

但是,使用这些工具尝试执行 .NET 调试时,会遇到一些重大困难:

  • 与在 Windows 上为 WinDbg 调试器设置符号的过程相比,配置可能很困难。
  • 核心转储文件很大,因为这些工具不知道 .NET Core 进程中使用了哪个内存区域,并且它们不能仅将内存信息剪裁到所需的内存信息。
  • 转储文件不可移植。 必须分析生成它们的 Linux 计算机上的转储文件。 如果要分析不同 Linux 计算机上的转储文件,则需要执行额外的步骤来为调试会话配置主计算机。

lldb

Lldb 是用于分析 .NET Core 转储的建议工具。 .NET SDK 包含用于正确配置 lldb 的有用工具。 但是,必须安装至少版本 3.9 才能对 .NET Core 执行此类调试分析。

若要安装 lldb 3.9 或更高版本,请使用程序包管理器(例如: sudo apt install lldb) 。

.NET Core 运行时和 SDK 中可用的工具和命令

多个有用的工具与 .NET Core 运行时一起包含在一起。 例如, createdump 作为 .NET Core 的每个运行时安装的一部分进行安装。

还可以开发自己的工具,或选择使用多个第三方工具。 Microsoft .NET Core 平台还包括一些有助于调试 .NET Core 问题的 .NET Core 工具。 这些演示包括以下内容:

  • dotnet-dump
  • dotnet-gcdump
  • dotnet-symbol

若要将这些工具与其他工具一起安装,必须安装 .NET Core SDK。 有关 .NET Core SDK 的详细信息,请参阅: .NET SDK 概述

注意

Procdump 也值得一提,尽管它不是 SDK 的一部分。 有关 ProcDump 选项的深入讨论,可在此部分末尾找到。

createdump

Createdump 安装在每个 .NET Core 版本中。 有关详细信息,请参阅 实现详细信息

Createdump 是在 Linux 中生成核心转储文件的最佳方式。 这是因为系统自动生成的转储文件可能不包含所有托管状态。 此外,某些 SOS 或 dotnet-dump 命令可能会显示类型和函数名称的“UNKNOWN”。

同样,使用 gdb 或 gcore 创建的手动转储文件不包含所有托管状态信息,某些 SOS 或 dotnet-dump 命令也可能会显示类型和函数名称的“UNKNOWN”。 捕获手动转储文件的推荐方法是使用 createdump 或其他一些 .NET Core 工具,例如 procdump。

下面是 createdump 的一些重要功能:

  • 自动生成最小大小的微型转会。
  • 使用非根用户进行配置很容易。
  • 可以使用它捕获按需(手动)或系统故障核心转储文件。
  • 检测到大多数堆栈溢出失败。

必须使用 lldb 3.9 或更高版本来分析使用 createdump 捕获的核心转储文件。

可以在 .NET Core 安装目录中找到 createdump。 若要查找此目录,请运行 dotnet --list-runtimes 该命令。 如以下屏幕截图所示,为两个版本的活动运行时创建了单独的 createdump 文件。

dotnet 命令的屏幕截图。

dotnet-dump

必须安装 .NET Core SDK 才能安装此工具。 .NET Core 3.0 SDK 中引入了 Dotnet-dump 。 它有助于收集和分析核心转储文件,而无需任何本机调试器。 它允许运行 SOS 命令来分析故障和垃圾回收器 (GC) 输出。

注意

Dotnet-dump 不是本机调试器。 因此,某些功能(如显示本机堆栈帧)不可用。 生成的转储文件不可移植,无法在 Windows 中打开它。

若要安装此工具,请运行以下命令:

dotnet tool install -g dotnet-dump

你将使用此工具捕获和分析即将推出的实验室部分中的核心转储文件。

dotnet-gcdump

这是另一个需要 .NET Core SDK 的工具。 Dotnet-gcdump 在 .NET Core 3.1 或更高版本中可用。

这是分析 GC 堆的有趣方法。 此工具背后的想法是,在许多情况下,调查不需要完整的进程转储文件。 因此,该工具仅捕获托管堆信息,并基于它生成报表。

最重要的是,此工具生成的转储文件是可移植的,可在 Windows 中的 PerfView 或 Visual Studio 中进行分析。

如此处所述,此工具触发了完整的垃圾回收,以将信息流式传输到“事件管道”以生成转储文件。

注意

由于目标进程中触发了完整的第 2 代垃圾回收,因此可以更改应用程序的性能特征。 如预期的那样,虽然信息写入核心转储文件,但线程将被挂起。 堆大小越大,将信息写入文件的暂停时间越长,线程将保持暂停的时间越长。

在以下情况下,此类核心转储文件中包含的信息将很有用:

  • 比较托管堆上按类型排序的对象数
  • 分析对象根
  • 确定哪些对象具有对哪种类型的引用
  • 关于堆上对象的其他统计分析

生成数据后,文件可以在创建数据的计算机外部导出,并且可以在 PerfView 或 Visual Studio 中对其进行分析。

若要安装此工具,请运行以下命令:

dotnet tool install -g dotnet-gcdump

你将使用此命令为即将推出的实验室部分中的 .NET Core 堆生成一些报告。

dotnet-symbol

Dotnet-symbol 是获取用于托管调试的符号的有用工具。 它已在 .NET Core 2.1 中引入。 至于前面提到的另外两个工具,这些工具还需要安装 .NET Core SDK。

Dotnet-symbol 下载任何给定核心转储文件所需的所有文件(符号、模块、SOS 和 COREclr 模块的 DAC)。

若要安装此工具,请运行以下命令:

dotnet tool install -g dotnet-symbol

你将使用此工具在即将到来的实验室部分中配置调试器。

procdump

ProcDump 的 Linux 版本也可用。 与 Windows 对应项相比,它具有一些有限的功能集。 它不支持 Windows 版本执行的每个功能。 例如,当进程崩溃或引发首次发生异常时,无法将其配置为收集核心转储文件。 然而,它仍然是一个强大的工具。

ProcDump 的以下命令行选项在指定条件下触发核心转储文件生成。

-C: CPU exceeds or equals a specified value (0 to 100 * nCPU)
-c: CPU is less than a specified value (0 to 100 * nCPU)
-M: The memory commit exceeds or equals a specified value (MB)
-m: The memory commit is less than a specified value (MB)
-T: The thread count exceeds or equals a specified value
-F: The filedescriptor count exceeds or equals a specified value

按照安装说明在环境中安装 ProcDump。

你将使用此工具捕获基于后续实验室部分中 CPU 使用率的核心转储文件。

有关选择 SDK 版本的说明

默认情况下,SDK 安装在“并排”配置中。 这意味着多个版本可以在单个计算机上一起运行。 选择要使用的 .NET Core 版本一文中详细说明了如何在运行 CLI 命令时选择版本。 但是,选择 SDK 版本的过程可以概括如下:

  • .NET Core 搜索 global.json 文件以迭代方式反向导航路径,从当前工作目录向上导航。
  • .NET Core 使用在找到的第一个 global.json 中指定的 SDK。
  • 如果未 找到任何global.json实例, .NET Core 将使用最新安装的 SDK。

例如,在测试 Linux 虚拟机上,应同时安装 .NET Core 3.1 和 5.0 SDK。 如果通过包括 --version 开关来运行 .NET Core,应会看到使用最新版本。

列表命令的屏幕截图。

现在,在当前目录(主目录)中创建 global.json 文件,并使用 cat 工具显式设置版本,如下所示。 然后,再次检查版本。 它现在会显示在global.json文件中放置的确切 SDK 版本。

cat json 命令的屏幕截图。

在运行某些 SDK 命令(例如使用 .NET Core new 命令创建应用程序)时,这一点很重要。 但是,使用 dotnet-dump 和 dotnet-gcdump 工具时,无需执行此操作。

无论选择哪个 SDK,.NET Core SDK 都会安装最新版本的工具。 例如,如果运行命令来安装 .NET Core SDK 3.1 的 dotnet-dump、dotnet-gcdump 和 dotnet-symbol 工具,则会下载并安装这些工具的最新版本,如以下屏幕截图中所示(其中安装了 dotnet-dump 和 dotnet-gcdump 的工具版本 5)。

dotnet 工具命令的屏幕截图。

以下文章是有关 .NET Core 工具的详细信息的绝佳资源:

注意

选择要使用的运行时版本不同于选择 SDK 版本。 如果要使用特定版本的 .NET 运行时,请使用 --fx-version <VERSION> 选项,如本文所述

后续步骤

现在可以开始故障排除实验室了。 在实验室中,你将了解如何使用此处讨论的工具来解决问题。

实验室 1.1 重现并排查崩溃问题