Chapter 08

その他のテクニック:不要な処理を省くハックたち

zk_phi
zk_phi
2020.09.24に更新

message を一時的に無効にする

IO は重い処理なので、もしセットアップ時に重要ではないメッセージをやたら表示するパッケージがある場合は、黙らせておくことで若干起動を高速化できます。

以前は message 関数を flet などで乗っ取る実装をしていましたが、現代の Emacs には inhibit-message という便利変数があるのでこれを活用します。

(let ((inhibit-message t))
  (require 'foo)
  (foo-initialize))

Magic File Name を一時的に無効にする

Emacs にはファイル名に応じて IO に独自の処理を挟む機構 (Magic File Name) があります。これはリモートのファイルにシームレスにアクセスするためなどに使われますが、起動処理の途中で欲しくなることはまずありません。しかし使わない場合でもファイル名のチェックは走ってしまうので、パッケージをロードする際などにはオーバーヘッドが発生します。

起動処理の間だけこれを無効にしておくことで、わずかに起動を速くすることができます。

そのためには、 init.el の頭で

(defconst my-saved-file-name-handler-alist file-name-handler-alist)
(setq file-name-handler-alist nil)

init.el のおわりで

(setq file-name-handler-alist my-saved-file-name-handler-alist)

のように設定しておけば ok です。

設定内容を妥協しなくても、ただ書いておくだけでちょっと速くなるのでおすすめです。

GC を減らす

Emacs Lisp ではメモリの free を人間が指示しないので、代わりにいらなくなったゴミは GC が集めます。しかし起動処理の途中でこれが走ってしまうと余計なオーバーヘッドになります。

そこで、起動の間だけ GC が走らないようにしておき、あとでメモリが必要になった時にまとめてお掃除してもらう方法があります。

Magic File Name と同様に、 init.el の頭で

(setq gc-cons-threshold most-positive-fixnum)

などとして GC の閾値を闇雲にでかい値にしておくことで GC を実質止めることができます。

もちろんこのままでは無限にメモリを食いつぶしてしまい、それはそれでパフォーマンスにも悪影響なので、 init.el のおわりでそれらしい値に戻しておく必要があります。

(setq gc-cons-threshold 16777216) ; 16mb

これもとりあえず書いておけば速くなる系なのでおすすめです。

early-init.el

Emacs 27 からは init.el の他に early-init.el というファイルも持てるようになりました。これは Emacs が起動した直後、 GUI の構築やパッケージのロードなどが行われるよりも前の、かなり初期の段階でロードされる設定ファイルです。

もともとパッケージシステム自体の設定などを行う用途で導入されましたが、 GUI の基本的な設定もここに入れておくと若干の効率化になります。

たとえばメニューバーやツールバーがいらない場合、 init.el で次のように設定するのが一般的だと思います。

(menu-bar-mode -1)
(tool-bar-mode -1)

しかしこれでは一度バー類が構築されてからまたすぐに消すという処理になってしまうので、無駄な計算が生じます。

early-init.el の中で、そもそもこれらのバー類はデフォルトで無効なものなのだと定義してしまえば:

(push '(menu-bar-lines . 0) default-frame-alist)
(push '(tool-bar-lines . 0) default-frame-alist)

この無駄な処理を省くことができます。

また、もし Emacs をいつも決まったフレームサイズで起動する場合 (フルスクリーンなど)、以下の行も early-init.el に加えておくと

(setq frame-inhibit-implied-resize t)

フォントが読み込まれたタイミングなどでフレームサイズの再計算が入ってチカチカする現象を防げます。