0

I read that changing the default garbage collector settings is not recommended https://lists.gnu.org/archive/html/help-gnu-emacs/2007-06/msg00243.html however I noticed it can make an impact on the startup speed.

I would like to prevent garbage collection only during startup then set back the GC threshold to its original value 800000.

I added this to early-init.el:

(setq gc-cons-threshold (* 50 1000 1000))

and then I added this to init.el:

(add-hook 'emacs-startup-hook
      (lambda ()
        "Restore defalut values after init."
        (setq gc-cons-threshold 800000)))

I can go a little bit further adding these lines into early-init.el as well:

(defvar default-file-name-handler-alist file-name-handler-alist)
(setq file-name-handler-alist nil)

Then setting the file-name-handler-alist back to its original value in init.el

(add-hook 'emacs-startup-hook
      (lambda ()
        "Restore defalut values after init."
        (setq file-name-handler-alist default-file-name-handler-alist)
        (setq gc-cons-threshold 800000)))

This change speeds up the startup even more reducing the waiting by 2-3 seconds.

I was wondering if it is necessary to separate these in two separates file, one chunk of code going into early-init.el and the other that sets back to original values in init.el or is it possible to put everything in early-init.el? In other idea, is it okay to add (add-hook 'emacs-startup-hook in the early-init.el file?

Zoli
  • 381
  • 1
  • 7

2 Answers2

1

Feel free to increase gc-cons-threshold and leave it there; it is unlikely to cause any noticeable problems. You don’t need to do anything fancy with early-init.el either, though it probably wouldn’t hurt anything. It’s just unlikely to help, either.

However, the most important thing the average Emacs user can do to improve startup times is to remove as many require calls as possible. It is habitual to require a package that you want to configure before setting any of its variables or calling any of its functions, but this is rarely necessary. Everything is autoloaded, so the package will be transparently loaded the first time you call any function defined in it. If set a variable that is marked as being defined in a package, you won’t get the usual warning about setting an undefined variable, and when that package is eventually loaded, the value you set will be used instead of any default value provided by the package.

The ideal situation is to set variables to configure the package, and to avoid calling any of its functions in your init file. Instead, call them in a mode hook, or a key binding, the emacs-startup-hook, or even on a 0.1 second timer if you have to. If you do this, Emacs will not have to read, parse, compile, and execute the package’s file(s) during startup. All of that takes time and generates garbage that might need to be collected.

If you use the use-package package, then you will get much of the same benefit as it explicitly does not require every package you configure. You’ll also be less tempted to add in a call to require.

Of course, you might still find the rare package that doesn’t have any autoload information, but you can detect those situations on a case–by–case basis and go back to calling require first.

db48x
  • 15,741
  • 1
  • 19
  • 23
  • Sorry but this did not answer my question. I use `use-package` and deferred anything that could be defered. I even used https://github.com/dholm/benchmark-init-el to eliminate everything that may cause delays. Even with that, my modification on GC and files make a huge impact on the startup time. – Zoli Nov 16 '22 at 10:43
  • Then keep it!.. – db48x Nov 16 '22 at 11:18
0

It's init.el that takes up the bulk of the loading time, so you need these changes to be effective during the processing of init.el. But AFAIK, you can put the emacs-startup-hook changes in your early-init.el as well, so you don't have to worry about it in init.el at all.

As @dbx48's answer points out, you can set gc-cons-threshold at the beginning of init.el and not worry about resetting it at the end (so you don't need to worry about it in early-init.el in that case). And the point about deferring loading of packages if possible is the one that most people should pay attention to, although it does not seem to apply to your case.

You can also put all the code of init.el inside a (let (...) ...) that redefines the variables you want (e.g. file-name-handler-alist to nil) for the duration of the let - that lets you avoid mucking around with early-init.el, but at the cost of making your init.el slightly more complicated. Or you can use a let around portions of your init file: that's harder to implement and maintain, but you might prefer it.

So there are alternatives, but I don't see anything wrong in doing it the way you did it.

NickD
  • 27,023
  • 3
  • 23
  • 42