--- title: "调试" description: "通过内置的 Debug Adapter Protocol 客户端设置断点、单步执行、查看变量和计算表达式。" --- OpenIDEA 通过 [Debug Adapter Protocol](https://microsoft.github.io/debug-adapter-protocol/)(DAP)调试程序。每种语言在自己的语言定义(`languages/.toml` 的 `[debugger]` 表)里指定调试适配器,调试运行配置时 IDE 会启动对应的适配器。命令和快捷键沿用 IntelliJ IDEA 的习惯,在 IDEA 里熟悉的操作大多可以直接用。 ## 启动调试会话 只要[运行配置](/zh/guide/run)带有调试适配器,就可以调试: - 点击 `main` 函数或测试旁边的边栏运行图标,选择 **调试**。 - 在工具栏的运行小部件里选好配置,点击调试按钮。 - **运行 › 调试** 调试当前选中的配置;**运行 › 调试…** 先选择配置;**运行 › 调试上下文配置** 调试光标处的程序或测试。 配置用哪个调试器,由 **运行 › 编辑配置…** 中的 **调试适配器** 字段决定。设为 **无** 即可关闭该配置的调试。 会话启动前,OpenIDEA 会先保存所有打开的文件。如果适配器没有安装,IDE 会给出提示;对于能自动安装的调试器,还会提供 **安装并调试**。 调试工具窗口(`⌘5` / `Alt+5`)每个会话一个标签页,包含两个视图: - **线程和变量**:线程列表、选中线程的栈帧,以及选中帧的变量。库代码的帧默认折叠,用 **显示所有帧** 展开。 - **Console**:程序输出,以及一个输入行,可在选中帧里计算表达式。用 **浏览控制台历史**(`⌘⌥E` / `Ctrl+Alt+E`)翻看之前输入过的表达式。 这两个视图的标签名目前还没有翻译,中文界面下也显示英文。 ## 支持的调试器 | 语言 | 调试适配器 | 获取方式 | | --------------------------------- | ---------------------------------------- | ------------------------------------------------------------------ | | Java | Microsoft java-debug(运行在 JDT LS 内) | 一键安装 | | Kotlin | kotlin-debug-adapter | 一键安装 | | C、C++、Objective-C、Swift | `lldb-dap` | 随 LLVM、Xcode(`xcrun -f lldb-dap`)和 Swift 6+ 工具链提供 | | Rust、Zig | CodeLLDB | 一键安装 | | Go | Delve(`dlv`) | 一键安装(通过 `go install`,需先装好 Go) | | Python | debugpy | 一键安装一份私有副本,所有解释器共用;也可以 `pip install debugpy` | | JavaScript、TypeScript(Node.js) | vscode-js-debug | 一键安装 | | C#、F# | netcoredbg | 一键安装 | | PHP | PHP Debug (Xdebug) | 适配器一键安装;PHP 本身需要装 Xdebug 3 扩展 | | Shell 脚本 | Bash Debug | 一键安装 | | Ruby | rdbg | `gem install debug` | | Elixir | ElixirLS 调试器 | 一键安装 | | Dart、Flutter | `dart debug_adapter` | 随 Dart / Flutter SDK 提供 | | OCaml | earlybird | `opam install earlybird` | | GDScript | Godot 编辑器 | Godot 4 | C 和 C++ 的配置也可以改用 GDB 14 及以上版本(`gdb -i dap`):在 **调试适配器** 字段里选 **GDB(C、C++)**。IDE 不会自动安装 GDB,需要自己装(`apt install gdb`、`dnf install gdb`、`brew install gdb`)。 一键安装在 **设置 › 语言和框架 › 语言服务器** 里,调试器和语言服务器列在一起,可以在这里安装、更新,或者指定自己安装的版本。 在 macOS 上,CodeLLDB 和 Delve 可能要开启开发者模式后才能启动或附加。执行一次 `sudo DevToolsSecurity -enable`,再重新启动调试会话。 ## 断点 点击行号即可添加或移除行断点,也可以用 **切换行断点**(`⌘F8` / `Ctrl+F8`)。在边栏上: - `⌥` 点击(`Alt` 点击)添加临时断点,命中一次后自动移除。 - `⇧` 点击(`Shift` 点击)添加不挂起程序的日志断点,并打开它的属性。 - 中键点击已有断点,启用或禁用它。 - 右键点击断点,编辑它的属性。 空行和只有注释的行不能加断点。默认情况下,行断点只能放在有调试器的语言文件里;如需放开限制,在 **设置 › 构建、执行、部署 › 调试器** 中打开 **允许在任意文件中设置断点**。 ### 断点属性 | 选项 | 作用 | | -------------------- | ---------------------------------------------------------------------- | | **已启用** | 不删除断点,只是打开或关闭它。 | | **挂起** | 关闭后,命中断点时程序继续运行(适合只记日志)。 | | **条件** | 只有表达式为真时才停下。 | | **命中次数** | 只有命中次数满足条件时才停下(语法由适配器决定,例如 `5` 或 `>= 5`)。 | | **“已到达断点”消息** | 每次命中时在控制台输出一条消息。 | | **计算并记录** | 每次命中时计算一个表达式并输出它的值。 | 断点对话框里也有这些选项,另外还有 **命中后移除**,勾选后断点变为临时断点。这些选项能否生效取决于适配器:条件、命中次数和日志消息都是 DAP 功能,大多数适配器支持,但不是全部。 ### 其他断点类型 | 类型 | 添加方式 | | ---------- | -------------------------------------------------------------------------------------------------------------------------------------- | | 临时行断点 | **切换临时行断点**(`⌘⌥⇧F8` / `Ctrl+Alt+Shift+F8`),或在边栏 `⌥` 点击 | | 方法断点 | 在方法声明上执行 **切换方法断点**,或在断点对话框里点 **添加方法断点** | | 字段监视点 | 在字段声明上执行 **切换字段监视点**,或在变量视图里对某个值选 **添加字段监视点**。可以选择在 **字段访问**、**字段修改** 或两者时挂起。 | | 异常断点 | 断点对话框的 **异常断点** 部分列出适配器提供的异常过滤器(例如已捕获和未捕获的异常)。 | 方法断点和字段监视点需要适配器支持 DAP 的函数断点和数据断点。debugpy、java-debug、js-debug 和 CodeLLDB 的异常过滤器会直接列出;其他适配器的过滤器要用它调试过一次才会出现。 ### 断点对话框 **查看断点…**(`⌘⇧F8` / `Ctrl+Shift+F8`)列出项目中的所有断点。可以在这里启用、编辑、删除断点和跳转到断点位置,打开 **静音断点**(暂时跳过所有断点而不删除),以及设置异常过滤器。**移除所有断点** 会清空列表。 断点按项目保存,重启后仍然保留。适配器无法设置的断点会标为未验证。 ## 单步执行 下面的命令在 **运行** 菜单和调试工具窗口的工具栏上。 | 命令 | macOS | Windows / Linux | | ---------------------------- | ------------- | --------------- | | 恢复程序 | `⌘⌥R` 或 `F9` | `F9` | | 暂停程序 | — | — | | 步过 | `F8` | `F8` | | 步入 | `F7` | `F7` | | 智能步入 | `⇧F7` | `Shift+F7` | | 步出 | `⇧F8` | `Shift+F8` | | 强制步过 | `⌥⇧F8` | `Alt+Shift+F8` | | 强制步入 | `⌥⇧F7` | `Alt+Shift+F7` | | 运行到光标处 | `⌥F9` | `Alt+F9` | | 强制运行到光标处 | `⌘⌥F9` | `Ctrl+Alt+F9` | | 显示执行点 | `⌥F10` | `Alt+F10` | | 重置帧 | — | — | | 停止 | `⌘F2` | `Ctrl+F2` | | 重新运行(在调试工具窗口中) | `⌘R` | `Ctrl+F5` | - 当前行有多个调用时,**智能步入** 可以选择要进入哪一个。 - 带“强制”的命令会忽略途中的断点。 - 程序挂起时,行上还会出现一个内嵌的“运行到光标处”按钮(调试器设置中的 **显示内嵌的“运行到光标处”按钮**)。 - **重置帧** 回到选中帧所在方法的开头,需要适配器支持。 ## 查看和修改值 程序挂起时: - **变量** 视图显示选中帧的变量。右键点击某个值,可以 **设置值…**(`F2`)、**复制值**、**复制名称**、**跳转到源代码**(`F4`)和 **添加到监视**。 - 监视表达式显示在变量视图顶部,每次停下或切换帧时重新计算。用 **添加到监视** 添加,用 **移除监视** 删除。 - 在编辑器里悬停变量会显示它的值。`⌥` 点击(`Alt` 点击)或 **快速计算表达式**(`⌘⌥F8` / `Ctrl+Alt+F8`)计算鼠标下的表达式或选中的内容。 - 局部变量的值会内联显示在使用它们的行尾。 - **计算表达式…**(`⌥F8` / `Alt+F8`)打开对话框,在选中帧里计算任意表达式,带历史记录,也能把表达式加入监视。 表达式使用被调试程序的语言,由调试适配器计算,能写什么取决于适配器。 ## 附加到正在运行的进程 **运行 › 附加到进程…**(`⌥⇧F5` / `Ctrl+Alt+F5`)列出调试器可以附加的本用户进程,按调试器分组: | 分组 | 进程 | | ---------------- | ------------------------------------------------------- | | Java (JDWP) | 带 JDWP agent 启动的 JVM | | Node.js | 用 `--inspect` 启动的 Node 进程 | | Python (debugpy) | Python 进程(注入 debugpy,或连接它的 `--listen` 端口) | | Go (Delve) | Go 二进制程序 | | Native (LLDB) | 其他进程;装了 CodeLLDB 就用它,否则用 `lldb-dap` | 输入文字可按名称、PID 或命令行过滤。 ### 远程调试配置 要调试在别处(另一台机器、容器里)启动的进程,在 **运行 › 编辑配置…** 里添加下面的配置。它们只能调试,不会启动进程。 | 配置 | 作用 | | ----------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- | | **远程 JVM 调试** | 附加到带 JDWP agent 启动的 JVM,或者等待 JVM 主动连接(**调试器模式**:**附加到远程 JVM** / **监听远程 JVM**)。表单会给出远程 JVM 需要加的启动参数。 | | **Go 远程** | 附加到用 `dlv --headless` 启动的 Delve 服务。 | | **Python 远程调试 (debugpy)** | 附加到用 debugpy 监听的 Python 进程。 | | **附加到 Node.js** | 附加到用 `--inspect` 启动的 Node.js 进程。 | | **PHP 远程调试 (Xdebug)** | 监听 Xdebug 连接,用于 php-fpm 或容器里运行的 PHP。 | | **附加到 Godot** | 调试 Godot 编辑器正在运行的游戏。 | 每个表单都有 **主机** 和 **端口** 字段,并给出远程端的启动命令。远程代码所在目录与本地不同时,用 **本地根目录** 和 **远程根目录** 做路径映射。 ## 各语言的特有功能 - **Java HotSwap**:**运行 › 调试操作 › 重新加载已更改的类** 编译改动,并把变化的类重新加载到正在运行的 Java 调试会话中。已经在执行的帧要等返回后才会用上新代码。保存后 JDT LS 自动完成构建时,IDE 也会提示是否重新加载。 - **Maven 和 Gradle**:调试 Maven 或 Gradle 配置时,IDE 会让 JVM 带上 JDWP agent 启动,再用 java-debug 附加上去。 - **Dart / Flutter**:Dart 会话运行时可以用 **热重载** 和 **热重启**。 - **PHP**:如果 PHP 解释器没有加载 Xdebug,断点会被跳过;会话启动时 IDE 会提示。 - **Python**:**设置 › 构建、执行、部署 › Python 调试器** 中有 **调试时自动附加到子进程** 和 **兼容 Gevent**。 ## 设置 **设置 › 构建、执行、部署 › 调试器**: - **命中断点时显示调试窗口**、**在断点处聚焦应用程序**、**进程终止时隐藏调试窗口**。 - **断点**:**允许在任意文件中设置断点**、**显示内嵌的“运行到光标处”按钮**。 - **数据视图**:**内联显示值**、**按字母顺序对值排序**、**鼠标悬停时显示值工具提示**、**选中代码时显示值提示**、**值工具提示延迟(毫秒)**。 - **单步执行**:**不要步入库脚本**(Python 只调试自己的代码;JavaScript 跳过 `node_modules` 和 Node.js 内部代码)。 ## 快捷键 | 操作 | macOS | Windows / Linux | | ----------------- | ------ | --------------- | | 调试 | `⌃D` | `Shift+F9` | | 调试…(选择配置) | `⌃⌥D` | `Alt+Shift+F9` | | 调试上下文配置 | `⌃⇧D` | — | | 切换行断点 | `⌘F8` | `Ctrl+F8` | | 查看断点… | `⌘⇧F8` | `Ctrl+Shift+F8` | | 计算表达式… | `⌥F8` | `Alt+F8` | | 附加到进程… | `⌥⇧F5` | `Ctrl+Alt+F5` | | 调试工具窗口 | `⌘5` | `Alt+5` | 以上都是默认键位,可以在[键位映射](/zh/guide/keymap)设置中修改。