事实证明,性能的巨大变化与垃圾回收有关。直到运行垃圾回收之前,对该函数的每次调用都会变慢。使用股票emacs,gc每隔几秒钟运行一次,但是我在init.el中增加了一行以缩短启动时间,从而将gc-cons-threshold设置为20 MB,这意味着gc很少运行,从而导致基准测试报告时间越来越慢,直到在几分钟后运行gc为止,然后时间会直线下降并再次变快。
恢复为默认的gc-cons-threshhold后,基准测试变得更加容易。
然后,我使用内置的事件探查器(M-x profiler-start
)对内存进行了探查,发现对语法pppss的调用引起了最多的分配,因此在进行一些优化以减少对语法pppss的调用后,我获得了可接受的性能。
使用jit-lock-mode(通过jit-lock-register添加功能)似乎是使多行字体锁定可靠工作的最简单方法,因此我选择了这种方法。
编辑:发现非常大的缓冲区中的性能仍然不够好之后,我花了很多时间来优化cpu的使用和分配,并使用内置的Emacs profiler(M-x profiler-start
)来衡量性能的提高。但是,在非常大的缓冲区中快速滚动时,Emacs仍会结结巴巴并挂起。删除我注册的jit-lock功能jit-lock-register
将消除结结和挂起,但是分析显示jit-lock功能在8毫秒左右完成,这应该足够快速以实现平滑滚动。删除呼叫jit-lock-register
并改为使用常规的font-lock-keywords匹配器可以解决此问题。
TLDR:这样做很慢,会结结巴巴:
(defun my-font-lock-function (start end)
"Set faces for font-lock between START and END.")
(jit-lock-register 'my-font-lock-function)
这样做很快,不会结巴:
(defun my-font-lock-function (start end)
"Set faces for font-lock between START and END.")
(defun my-font-lock-matcher (limit)
(my-font-lock-function (point) limit)
nil)
(setq font-lock-defaults
(list
...
;; Note that the face specified here doesn't matter since
;; my-font-lock-matcher always returns nil and sets the face on
;; its own.
`(my-font-lock-matcher (1 font-lock-keyword-face nil))))