强曰为道
与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

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, gcmhGC 优化、长行处理
包冲突C-h m, C-h k检查模式、键绑定
编码乱码describe-coding-system设置 UTF-8
TRAMP 慢tramp-verbose, ControlMaster禁用 VC、复用连接
内存泄漏memory-report, list-timers清理缓冲区和进程
Elisp 调试Edebug, messageinstrument + 断点

19.9 扩展阅读


← 上一章 第 18 章:Docker 集成 | 下一章 → 第 20 章:最佳实践