emacs慢一大部分是gc,gc慢主要是分析大量对象是否可回收慢,其实释放不用对象空间不耗费性能。
单线程花太多时间分析gc,就会卡emacs。
有没有一种可能,在emacs外部分析emacs的内存特征和重建gc对象扫描,这样没扫完就持续扫,一旦扫完同时emacs空闲,就让emacs直接释放内存。
这样做会增加外部进程内存占用,但绝对不卡emacs,性能提升会让所有elisp插件受益。
emacs慢一大部分是gc,gc慢主要是分析大量对象是否可回收慢,其实释放不用对象空间不耗费性能。
单线程花太多时间分析gc,就会卡emacs。
有没有一种可能,在emacs外部分析emacs的内存特征和重建gc对象扫描,这样没扫完就持续扫,一旦扫完同时emacs空闲,就让emacs直接释放内存。
这样做会增加外部进程内存占用,但绝对不卡emacs,性能提升会让所有elisp插件受益。
现在流行的操作系统安全策略 (ASLR) 都不让这么搞了吧
现在scratch/igc分支使用感受快了很多,不过没有了解实现方法
感觉上在 emacs 内部开些线程做并发 GC 就行? 外部进程做 GC 暂时没想到什么特别的优势.
瞎猜现在 igc 分支上用的 GC 应该有这种设计, 一般 mark stack/reg 之类的地方需要停一下, 大部分 mark 和 sweep 就可以放在其他线程了, 然后 compaction 阶段也会停一次. 整个 GC 还是会有一些 pause, 不过比在主线程 GC 要好挺多.
出于安全考虑外部扫描基本不可行,内部专门开一个线程做这事儿?
还好把,
1 pe文件自己的重定位可以直接改pe结构的字段来关闭
2 堆内存也可以指定分配地址,如果是外部进程,也不会冲突
刚去看了下igc分支的实现 emacs/src/alloc.c at 0756b1f2f5452d715396f66d887c137776e360ca · emacs-mirror/emacs · GitHub
和原来的几个区别
1 所有的标记操作不需要在这里做了
#ifndef HAVE_MPS
struct gc_root_visitor visitor = { .visit = mark_object_root_visitor };
visit_static_gc_roots (visitor);
mark_pinned_objects ();
mark_pinned_symbols ();
mark_lread ();
mark_terminals ();
mark_kboards ();
mark_threads ();
mark_charset ();
mark_composite ();
mark_profiler ();
#ifdef HAVE_PGTK
mark_pgtkterm ();
#endif
#ifdef USE_GTK
xg_mark_data ();
#endif
#ifdef HAVE_HAIKU
mark_haiku_display ();
#endif
#ifdef HAVE_WINDOW_SYSTEM
mark_fringe_data ();
#endif
#ifdef HAVE_X_WINDOWS
mark_xterm ();
mark_xselect ();
#endif
#ifdef HAVE_ANDROID
mark_androidterm ();
#ifndef ANDROID_STUBIFY
mark_sfntfont ();
#endif
#endif
#ifdef HAVE_NS
mark_nsterm ();
#endif
mark_fns ();
#endif // not HAVE_MPS
2 实际的清理工作也不需要这里做了
#ifndef HAVE_MPS
queue_doomed_finalizers (&doomed_finalizers, &finalizers);
mark_finalizer_list (&doomed_finalizers);
/* Must happen after all other marking and before gc_sweep. */
mark_and_sweep_weak_table_contents ();
eassert (weak_hash_tables == NULL);
eassert (mark_stack_empty_p ());
gc_sweep ();
unmark_main_thread ();
#endif
不过他用mps也是用的协作式的方式,这种貌似不是在独立的线程,对于用户体验而言没有根本性的提升
确实, 现在的改法 emacs 里面不会直接调用 gc 了, 应该是在 alloc 之类的地方偷一点 cpu 时间做 concurrent gc. 看 mps 的设计应该是能在另一个线程做一些 mark 之类的事情, 但是恐怕得 benchmark 下看看才知道有没有实际收益.
目前对用户体验可能也有点提升, mps 可以做 incremental gc, 就算是在主线程, 理想情况可以把 gc 时间分散成多个小阶段, 用户的感受到的长时间停顿会少点.
感觉上比起依赖外部 gc 可能还是针对自己的需求写一个比较好. 但是 emacs 历史包袱有点重, 看 igc 分支的改动, gc 和 lisp 还有编辑器一些功能都耦合在一起了, 改起来似乎也挺头疼的.