Emacsで現在利用しているメモリを確認する


これは、Emacs Advent Calendar 2020 の23日目の記事です。 12月書けなくて他の人に書いてもらったのだけど、せっかくまだ書かれてない日が残ってたのでアドベントカレンダーとして書いてみる。

さて、Emacsは明示的にGarbage Collectionがあるエディタであり、利用していると時々GCが発動する。

そして、GCが発生すると動きが止まってしまうので、GC発動の閾値のチューニングがおこなわれる。 特に起動時にGCが発生すると、起動時間に影響があるため起動時だけ一時的に閾値を上げるチューニングをする人すらいる。

これまで、感覚でまあこんなもんだろ、で閾値を設定していた。 だが、実際どれぐらい使っているかがわかれば適切な閾値設定ができるのではないか、 と考え、GC後にもどれだけのメモリを利用しているのかを出力するようにした。

GC後に現在の使用中のメモリを表示

あまり聞いたことなかったので一筋縄じゃいかないのかもと思ってソースコードも見ていたのだけど、 結局 garbage-collect の実行後で以下のリストが返されるので、それを加工すればよかった。

(オブジェクト種別名 オブジェクトサイズ オブジェクト数)

オブジェクトによっては、これに確保しているけど利用していない領域数も含めてくれるのもあったが、 確実に必要なものだけカウントすることにした。

ということで、以下のように garbage-collect にアドバイスを加えて完了。

(defun grugrut/gc-debug-function (str)
  (let ((sum 0))
     (dolist (x str)
        (setq sum (+ sum (* (cl-second x) (cl-third x)))))
     (message "Used Memory: %d MB" (/ sum (* 1024 1024)))))
(advice-add 'garbage-collect :filter-return #'grugrut/gc-debug-function)

GCMH

garbage collectionは少なからずSTW(Stop The World)が発生してしまうので、 できるだけストレスがないようにGCのチューニングはしたい。

とはいえ、GCが発生しにくいようにチューニングするだけであり、GC自体はどうしても必要である。

この影響をできるだけ抑えるアプローチの一つがGCMH(Garbage Collection Magic Hack)である。

アプローチの内容はいたってシンプルで、操作がおきないときにGCを動かせば、 STWしたとしても利用者は気にならないよね、というもの。

GCMHは標準で入っているので、有効化すればすぐに使える。

(leaf gcmh
  :ensure t
  :diminish gcmh
  :custom
  (gcmh-verbose . t)
  :config
  (gcmh-mode 1))

Emacs28のメモリ管理

ちなみに、利用領域の取得方法を調べてるときにわかったのだけど、Emacs28から garbage-collect-maybe という新しいGC用の関数が増えるらしい。

https://emba.gnu.org/emacs/emacs/-/blob/master/etc/NEWS#L2085

NEWSを見る限りGCのトリガーを早めに発行するためのものとのこと。

特に書かれてないので推測だけど、GCの頻発を嫌って単純に閾値を上げると、 真にGCが必要な場合にその処理時間が長くなってしまう。

そのためGCしてもいいよってときにこれを実行することで、 都合がつくときはすぐ終わるGCを発動させて、それ以外のときにGCが発生しにくい制御をすることができるのでしょう。 ソースコード読む限り、単に閾値をこの関数経由のときだけ小さくするだけで、 GC自体は変わらなそうなので、これ使っても時間がかかるときはかかると思う。

28のリリースが近付けばもっと情報が出てくるかもしれないので楽しみ。 例えば、GCMHと組み合わせることで、いいかんじに裏でGCしてくれると嬉しい。


See also

comments powered by Disqus