优化Emacs启动时间


#1

分析慢的原因

首先下载 benchmark-init 这个插件, 在配置最开始的位置写下配置:

(let (
      ;; 加载的时候临时增大`gc-cons-threshold'以加速启动速度。
      (gc-cons-threshold most-positive-fixnum)
      ;; 清空避免加载远程文件的时候分析文件。
      (file-name-handler-alist nil))
  (require 'benchmark-init-modes)
  (require 'benchmark-init)
  (benchmark-init/activate)

    ;; 下面才写你的其它配置
)

启动完毕后,执行 M-x benchmark-init/show-durations-tree 命令,这个命令会递归的打印出所有插件的耗时明细。

优化: 动态加载插件

比如下面这个配置会禁止Emacs退出的时候问后台进程是否需要杀掉的问题,会用到 noflet 这个库。 一般你可以这样写:

(require 'noflet)

(defadvice save-buffers-kill-emacs (around no-query-kill-emacs activate)
  "Prevent annoying \"Active processes exist\" query when you quit Emacs."
  (noflet ((process-list ())) ad-do-it))

这样写的坏处是,Emacs没有退出时不会执行这个advice, 但是一启动就会加载 noflet 这个库, 浪费了启动时间。

优化的方式如下,把要调用的库在用的时候再加载,改成这样就好很多:

(defadvice save-buffers-kill-emacs (around no-query-kill-emacs activate)
  "Prevent annoying \"Active processes exist\" query when you quit Emacs."
  (require 'noflet)
  (noflet ((process-list ())) ad-do-it))

优化: 按键触发加载

第二种优化方式主要用我头几天写的 lazy-load 技术来做。 把 90% 的插件放到运行时第一次按键时再加载,而不是启动的时候就加载好。 因为lazy-load那篇文章已经详细说明了用法,这里就不再复述。

最后

用我上面的三个优化步骤,可以把Emacs启动时间减少到 1/10.

Enjoy! :wink:


#2

走个题,如果用use-package,把非必要packages(对于我来说就是除了counsel和org的其他)全部加上:defer 3, :defer 5就可以了,100+以上packages启动耗时5秒


#3

直接上图,258 package 1.6s。 用use-package,加上一些其他优化技巧,2s左右很正常。命令行下0.8s左右。


#4

我的配置有184 (length load-path) 个package, 优化后启动只需要 0.6s %E6%88%AA%E5%9B%BE_2019-05-13_01-20-30

如何优化:

  • 参考 doom-emacs 作者写的 how-is-dooms-startup-so-fast
  • 除上面说的benchmark-init外,还有一个esup可供测试
  • 使用use-package以autoload所有插件
  • 启动时不要直接打开相应的mode, 可以使用after-init-hook, emacs-startup-hook,或者 window-setup-hook,比如可以用
    (use-package yasnippet
       :hook (after-init . yas-global-mode))
    
  • 除了after-init-hook外,还可以自定义启动hook并且延时运行,这样可以减少很多启动时间
    (defvar maple-init-hook nil
      "Custom init hook.")
    
    (maple/add-hook 'emacs-startup-hook
       (run-with-idle-timer 0.1 nil (lambda() (run-hooks 'maple-init-hook))))
    
  • 最后你会发现大量的启动时间都消耗在(package-initialize)(我还在使用26的版本,27貌似不需要这行),所以之前我参考doom-emacs写了一个maple-package来加快emacs的启动,使用之后可以提升0.3s的启动时间

当然,这里的启动是指打开一个空的buffer,如果打开一个python文件,就会花费更多时间,更好的方式是使用emacs --daemon, 然后用emacsclient


#5

我300个包,800ms,还包括启动两个sever服务


#6

windows下也能用吗?我windows下的启动时间2分钟,痛苦的很


#7

windows就是慢,不过不至于两分钟…


#8

我用spacemacs,400个包,启动时间8点几秒。。。


#9

300多package 1.6s,有一大半在package-initialize了


#10

emacs版本?使用过类似use-package的延迟加载没?需要经常启动emacs吗?


#11

emacs 26,同样的配置,ubuntu底下就快的很, windows底下干掉了一大堆包还是慢,6秒左右


#12
╼►[benchmark-init/root nil 6567ms]
  ├─[etags require 196ms]
  │ ╰─[xref require 204ms]
  │   ╰─[project require 218ms]
  ├─[company-dabbrev require 31ms]
  ├─[company-capf require 31ms]
  ├─[company-cmake require 78ms]
  ├─[company-clang require 78ms]
  ├─[company-eclim require 78ms]
  │ ╰─[company-template require 47ms]
  ├─[cl require 215ms]
  ├─[rx require 218ms]
  ├─[~/.emacs.d/company-statistics-cache.el load 0ms]
  ├─[company-statistics require 31ms]
  ├─[~\.emacs.d\abbrev_defs load 16ms]
  ├─[default load 281ms]
  ├─[paren load 250ms]
  ├─[cus-start require 204ms]
  ├─[cus-load require 218ms]
  ├─[init-better-defaults require 764ms]
  │ ├─[grep require 187ms]
  │ ├─[compile require 218ms]
  │ │ ╰─[comint require 203ms]
  │ │   ├─[ansi-color require 189ms]
  │ │   ╰─[ring require 203ms]
  │ ├─[ibuffer require 207ms]
  │ │ ╰─[ibuffer-vc require 78ms]
  │ │   ╰─[ibuf-ext require 200ms]
  │ ├─[thingatpt require 187ms]
  │ ├─[popwin require 141ms]
  │ ╰─[filenotify require 188ms]
  ├─[init-keybindings require 203ms]
  ├─[init-company require 0ms]
  ├─[init-cc-mode require 16ms]
  ├─[init-yasnippet require 422ms]
  │ ╰─[yasnippet require 219ms]
  ├─[init-elisp require 0ms]
  ├─[init-lisp require 78ms]
  ├─[init-hippie-expand require 0ms]
  ├─[init-ibuffer require 218ms]
  ╰─[init-elpa require 250ms]

#13

Windows 下主要是读取文件慢,是通过msys编译的,不是原生API调用天生就慢。去掉一些比较大的包会有好转。还有一个办法就是在WSL下用。不过,还是会慢不少。