Emacs 完全指南 / 第 19 章:故障排除
第 19 章:故障排除
19.1 性能优化
启动速度优化
;;; === early-init.el 性能优化 ===
;; 1. 提高垃圾回收阈值(启动时禁用 GC)
(setq gc-cons-threshold most-positive-fixnum)
(add-hook 'emacs-startup-hook
(lambda ()
(setq gc-cons-threshold (* 16 1024 1024)))) ; 16MB
;; 2. 禁用文件名处理器(启动时)
(defvar default-file-name-handler-alist file-name-handler-alist)
(setq file-name-handler-alist nil)
(add-hook 'emacs-startup-hook
(lambda ()
(setq file-name-handler-alist default-file-name-handler-alist)))
;; 3. 禁用 GUI 元素
(push '(menu-bar-lines . 0) default-frame-alist)
(push '(tool-bar-lines . 0) default-frame-alist)
(push '(vertical-scroll-bars) default-frame-alist)
;; 4. 延迟加载 package.el
(setq package-enable-at-startup nil)
启动时间测量
;; 测量启动时间
(add-hook 'emacs-startup-hook
(lambda ()
(message "Emacs 启动耗时: %.2f 秒 (%d 次垃圾回收)"
(float-time (time-subtract after-init-time before-init-time))
gcs-done)))
;; 使用 benchmark-init 测量各包加载时间
(use-package benchmark-init
:config
(add-hook 'after-init-hook 'benchmark-init/deactivate))
;; M-x benchmark-init/show-durations-tree → 查看加载时间树
运行时性能
;; 1. 优化 GC
(setq gc-cons-threshold (* 32 1024 1024)) ; 32MB
(setq gc-cons-percentage 0.6)
;; 使用 gcmh(垃圾回收管理器)
(use-package gcmh
:config
(gcmh-mode 1))
;; 2. 优化长行处理
(setq-default bidi-paragraph-direction 'left-to-right)
(setq bidi-inhibit-bpa t)
;; 3. 优化大文件
(setq large-file-warning-threshold (* 50 1024 1024)) ; 50MB
;; 4. 优化字体渲染
(setq inhibit-compacting-font-caches t)
;; 5. 优化进程通信
(setq read-process-output-max (* 3 1024 1024)) ; 3MB(LSP 需要)
19.2 诊断工具
内置诊断
;; 查看内存使用
M-x memory-report
;; 查看变量值
C-h v gc-cons-threshold RET
;; 查看加载的库
M-x list-load-path-shadows ; 检查重复加载
M-x describe-library ; 查看库位置
;; 查看进程
M-x list-processes
;; 查看系统信息
M-x emacs-version
M-x emacs-uptime
性能分析
;; CPU 分析
M-x profiler-start → 选择 CPU
... 正常使用 ...
M-x profiler-report → 查看报告
M-x profiler-stop
;; 内存分析
M-x profiler-start → 选择 memory
... 正常使用 ...
M-x profiler-report → 查看报告
;; profiler-report 操作:
;; TAB → 展开/折叠
;; S-TAB → 全部展开/折叠
;; C-u RET → 查看函数源码
包加载分析
;; 查看哪些包加载时间最长
;; 方法 1:benchmark-init
(use-package benchmark-init
:config
(add-hook 'after-init-hook 'benchmark-init/deactivate))
;; 方法 2:手动测量
;; (benchmark 1 (require 'some-package))
;; 方法 3:查看 use-package 加载报告
;; M-x use-package-report
(setq use-package-verbose t) ; 日志输出
19.3 常见问题与解决方案
问题 1:启动慢
| 症状 | 原因 | 解决方案 |
|---|
| 启动 > 5 秒 | 加载过多包 | 使用 :defer t 延迟加载 |
| 启动卡住 | 包下载超时 | 设置镜像源/代理 |
| 启动闪烁 | GUI 初始化延迟 | early-init.el 禁用 GUI 元素 |
| 每次都编译 | 字节码过期 | 检查 .elc 文件时间戳 |
;; 排查步骤:
;; 1. emacs -q → 确认是否是配置问题
;; 2. emacs --debug-init → 查看启动错误
;; 3. benchmark-init → 找到耗时包
;; 4. 逐个禁用包 → 二分法定位
问题 2:运行卡顿
| 症状 | 原因 | 解决方案 |
|---|
| 输入延迟 | 垃圾回收太频繁 | 提高 gc-cons-threshold |
| 滚动卡顿 | 长行处理 | 设置 bidi-paragraph-direction |
| 保存慢 | 钩子函数太多 | 检查 before-save-hook |
| LSP 卡顿 | 语言服务器问题 | 调整 lsp-idle-delay |
;; 实时监控 GC
(use-package explain-pause-mode
:config
(explain-pause-mode 1))
;; 当检测到卡顿时会在模型栏显示警告
问题 3:包冲突
;; 症状:功能异常或报错
;; 诊断方法:
;; 1. 查看当前激活的次模式
C-h m
;; 2. 查找按键绑定冲突
C-h k <问题按键>
;; 3. 查找函数定义
C-h f <问题函数>
;; 4. 查看包加载顺序
;; (setq use-package-verbose t)
;; 5. 检查多个包同时修改同一功能
;; 常见冲突:
;; - evil + god-mode
;; - multiple-cursors + evil
;; - company + corfu(不要同时使用)
;; - flycheck + flymake(某些 LSP 客户端会启动 flymake)
问题 4:编码问题
;; 症状:中文乱码
;; 解决:
;; 设置编码
(set-language-environment "UTF-8")
(set-default-coding-systems 'utf-8)
(set-terminal-coding-system 'utf-8)
(set-keyboard-coding-system 'utf-8)
(set-selection-coding-system 'utf-8)
(set-buffer-file-coding-system 'utf-8-unix)
;; 文件保存编码
(setq default-buffer-file-coding-system 'utf-8-unix)
;; 读取文件时自动检测
(prefer-coding-system 'utf-8)
;; 处理 Windows 换行符
(setq-default buffer-file-coding-system 'utf-8-unix)
问题 5:TRAMP 连接问题
;; 症状:TRAMP 连接慢或失败
;; 诊断:
;; 1. 提高日志级别
(setq tramp-verbose 6)
;; 查看日志:C-h C-f /ssh:user@host RET
;; 2. 优化连接速度
(setq tramp-default-method "ssh")
(setq tramp-auto-save-directory "~/.emacs.d/tramp-autosave")
;; 3. 使用 ControlMaster 复用连接
;; ~/.ssh/config:
;; Host *
;; ControlMaster auto
;; ControlPath ~/.ssh/sockets/%r@%h-%p
;; ControlPersist 600
;; 4. 禁用版本控制检查(大幅提速)
(setq vc-ignore-dir-regexp
(format "\\(%s\\)\\|\\(%s\\)"
vc-ignore-dir-regexp
tramp-file-name-regexp))
;; 5. 指定 SSH 参数
(setq tramp-ssh-controlmaster-options
"-o ControlMaster=auto -o ControlPath='%%C' -o ControlPersist=no")
问题 6:内存泄漏
;; 症状:Emacs 内存持续增长
;; 诊断:
;; 1. 查看内存使用
M-x memory-report
;; 2. 检查 buffer 列表
M-x list-buffers → 看是否有大量特殊缓冲区
;; 3. 检查进程
M-x list-processes → 看是否有僵尸进程
;; 4. 检查 timer
M-x list-timers → 看是否有异常 timer
;; 5. 强制 GC
M-x garbage-collect
19.4 调试 Elisp 代码
Edebug(内置调试器)
;; 1. 在函数上放置光标
;; 2. C-u C-M-x → instrument 函数(进入调试模式)
;; 3. 调用该函数
;; 4. Edebug 会在每个 S-表达式处暂停
;; Edebug 操作:
;; SPC → 继续执行到下一个断点
;; n → 步进(step over)
;; s → 步入(step into)
;; o → 步出(step out)
;; c → 继续到下一个断点
;; g → 继续执行
;; b → 设置断点
;; B → 删除断点
;; e → 评估表达式
;; q → 退出调试
;; 取消 instrument:
;; C-M-x → 在函数上执行
Message 调试
;; 最简单的调试方式
(defun my-function ()
(message "DEBUG: 进入函数,参数: %s" arg)
;; ... 处理 ...
(message "DEBUG: 结果: %s" result)
result)
;; 查看消息:切换到 *Messages* 缓冲区
;; C-h e → 打开 *Messages*
条件断点
;; 使用 edebug 条件断点
;; 1. C-u C-M-x instrument 函数
;; 2. 在代码处按 b 设置断点
;; 3. 按 B 编辑断点条件
;; 输入条件表达式,如 (> x 100)
19.5 日志与错误查看
;; *Messages* 缓冲区
;; C-h e → 查看所有消息和警告
;; *Warnings* 缓冲区
;; 自动弹出,包含警告信息
;; *Backtrace* 缓冲区
;; 出错时自动弹出
;; (setq debug-on-error t) → 遇到错误时自动进入调试
;; *Compile-Log* 缓冲区
;; 包编译错误和警告
;; Flycheck 错误
;; C-c ! l → 列出所有错误
;; C-c ! v → 查看当前行错误详情
19.6 恢复损坏的配置
# 方案 1:使用安全模式启动
emacs -q # 不加载任何配置
emacs -Q # 不加载配置和 site-wide 设置
# 方案 2:只加载 minimal 配置
emacs -q -l ~/.emacs.d/minimal-init.el
# 方案 3:调试启动错误
emacs --debug-init
# 方案 4:备份恢复
# 定期备份 ~/.emacs.d/
cp -r ~/.emacs.d ~/.emacs.d.bak.$(date +%Y%m%d)
# 方案 5:Git 管理配置
cd ~/.emacs.d
git init
git add .
git commit -m "initial config"
19.7 常用诊断命令汇总
| 命令 | 说明 |
|---|
C-h e | 查看 Messages |
C-h m | 查看当前模式 |
C-h k | 查看按键绑定 |
C-h f | 查看函数文档 |
C-h v | 查看变量文档 |
C-h l | 查看最近输入的按键 |
M-x list-processes | 列出进程 |
M-x list-timers | 列出定时器 |
M-x memory-report | 内存报告 |
M-x profiler-start | 开始性能分析 |
M-x profiler-report | 查看分析报告 |
M-x garbage-collect | 强制垃圾回收 |
M-x describe-bindings | 查看所有键绑定 |
M-x describe-face | 查看 face 属性 |
19.8 本章小结
| 问题类别 | 诊断方法 | 优化方向 |
|---|
| 启动慢 | benchmark-init, --debug-init | 延迟加载、禁用 GC |
| 运行卡 | profiler, gcmh | GC 优化、长行处理 |
| 包冲突 | C-h m, C-h k | 检查模式、键绑定 |
| 编码乱码 | describe-coding-system | 设置 UTF-8 |
| TRAMP 慢 | tramp-verbose, ControlMaster | 禁用 VC、复用连接 |
| 内存泄漏 | memory-report, list-timers | 清理缓冲区和进程 |
| Elisp 调试 | Edebug, message | instrument + 断点 |
19.9 扩展阅读
← 上一章 第 18 章:Docker 集成 | 下一章 → 第 20 章:最佳实践