Hacker News new | past | comments | ask | show | jobs | submit login
The original magic Emacs garbage collection hack (2019) (akrl.sdf.org)
126 points by simonpure 10 months ago | hide | past | favorite | 42 comments



I personally use this (alongside an extremely high threshold):

    (add-function :after
                  after-focus-change-function
                  (lambda () (unless (frame-focus-state) (garbage-collect))))
So Emacs GCs whenever it loses focus (i.e. I'm looking at some docs in a browser or whatever). This works great for me - it's rare that I notice it still cleaning up when I switch back.


Wait… you switch away from Emacs?


Humoristic surprise aside, I think this trick just feels neat and does not actually solve the problem when it matters most, because even if you often switch between apps, there are still going to be times when you don't.

Times when you're just staring at compiler output or something heavy like that, and now you need a different GC trigger to save the day... and if you have that, then you do not need the trick.


All I can say is that never happens to me. I moved to this after being annoyed by other approaches, especially idle ones where I'd pause to think only for the GC to kick in. Whereas if Emacs has lost focus, I'm between thoughts anyway so my flow is never interrupted.


I work on the Firefox GC, so I guess I'm biased, but this doesn't seem like the greatest idea if you use it exactly as proposed. By setting a really high threshold for automatic GC scheduling, you're guaranteeing that memory usage is going to grow quite a bit as long as you're even slightly active (15 seconds is a long time to be idle!), which means (1) whatever application you're switching to will have had its pages pushed out and will start responding more slowly as it faults them back in, and (2) 15 seconds into using that application, you'll get a system-wide stutter as the emacs GC faults all of its massive pile of pages back into physical memory in order to scan through the reference graph.

Of course, you'll probably blame both of those on whatever application you're using, so in a way from emacs's point of view this is all free!

I'm not saying the underlying idea is bad. Using idle time for GC is good. 1GB just seems like an awfully high threshold for non-idle time. It's giving up on the idea of "small enough to be unnoticeable" pauses. (Though the right way to do that would be to have an incremental GC, but that has costs of its own.)

Personally, I guess I'd want to try a lower non-idle heap threshold, plus a shorter idle time threshold (15 seconds seems quite long, and a shorter time increases the probability of the GC'd pages still being in RAM), plus using focus as an idle signal.

And maybe play with using variable heap size thresholds, eg base the trigger off of both how long emacs has been idle plus the size of the heap just after the previous collection. So you might say that the heap threshold is 100% of the previous heap size at 15 seconds, 400% at 5 seconds, 1000% when non-idle. Or min(10x previous, 20MB) when non-idle, perhaps, where 20MB is adjusted to take an amount of time that is barely noticeable? But that's adding complexity. I guess I should enable GC logging to see how long these collections typically take; I haven't noticed a lot of pauses in the first place.


> It's giving up on the idea of "small enough to be unnoticeable" pauses

If emacs already had this, then none of these GC hacks would be needed?


Of note, this is a post by Andrea Corallo, the legend who brought native compilation to emacs lisp a few years back


Is this the default now ?


It's now the default on the development branch: https://git.savannah.gnu.org/cgit/emacs.git/commit/?id=3328c...

It's _not_ the default in any official release, yet. Although plenty of distros have either a separate package enabling it (or have enabled it in the main package)


Not yet. I believe, it is discussed for Emacs 30. Meanwhile if you are willing to install Emacs 29 as a snap (https://snapcraft.io/emacs) you can enjoy the benefits it brings w/o needing to compile your Emacs binary. I use it as my daily driver and did not have any issues.


Yes, since 28.1, last April.


AITA for pointing out that we've pushed the "barbarian practice of memory management" to the user?


Depends who you ask. I personally rarely noticed memory management overhead when using Emacs. If it indeed behaves janky, then the ancient defaults are to blame. Automated memory management is very difficult in the general case, but the strategy from TA sounds very reasonable and sane on modern machines: UIs typically have infrequent peaks of high activity and long breaks in between.

Would be interesting to see how many users are actually using it on computers made in the last century, where the default strategy might be more appropriate.


Yeah, I was trying to be funny.

But it’s still interesting to me that this thread is filled with users talking about their techniques for forcing a GC while they’re getting coffee or switching tabs.

The fact that in 2024 we’re talking about users (expert users, to be fair) changing setting in their apps to optimize GC pauses makes me think something has gone wrong somewhere.

But maybe I’m just being mean because I mostly use C++.

Goes to show that it’s trade-offs all the way down.


Yes, it is appreciated :-)

As I said, Emacs has many ancient defaults that many people have to fiddle with to make the editor theirs. Some of them is because of a slow drift of user preferences over the generations. But memory management strategy is one area where objectively a new default strategy would make a lot of sense. One which automatically adapts to RAM size, since Emacs scales down so well, unlike its competing memory guzzlers.


No. Assholes would remove the ability to tweak a program.


cf. https://github.com/emacsmirror/gcmh (the author's [=Andrea Corallo's] Emacs package "GCMH - the Garbage Collector Magic Hack")


Very clever, anyway I put a very high gc-cons-threshold in my .emacs and I never had big issues.

The reality is emacs is complex but today computers with 8GBs of ram has about 1000x memory of the original emacs target (a machine with 8 MB of RAM) and even faster processors.

Now I am in love with vscode, but I think I need to come back to emacs :) sometimes


> this is just a polite way to say: "NEVER garbage collect unless we are potentially causing the OS to swap pages."

It's not straightforward to guess where this threshold is because it depends on the behavior of other applications. The OS could already be swapping before your process even started.


I've done this for a while, increasing the threshold and collecting every time I tab away from an emacs window

(setq gc-cons-threshold 100000000) (add-function :after after-focus-change-function 'garbage-collect)


The refinement in https://news.ycombinator.com/item?id=39191012 seems useful.


I use:

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

I have 256GB RAM locally so I might as well use it.


Having a lot of RAM doesn't mean you have no need for garbage collection. By definition, garbage collected programs continuously leak memory, and consume all the available resources on the machine.

Even setting it to 256GB is a much better idea than just turning off GC. I recommend to maybe halve that to leave just enough RAM for Chrome.


Right, but if I have so much RAM available, it practically doesn't matter.

I've been running emacs since I logged in at 9am, edited ~100 different files. Many LSP inferior-processes running and emacs is currently sitting at 1 whole gigabyte resident memory.

What's more is that I would say this is a particularly light day for me and emacs.

I have literally never, never, not once ever had an issue with this much RAM and essentially turning gc off in emacs.


> I've been running emacs since I logged in at 9am

Yes, but which year ?


This one.


i don't know, my experience in practice is that turning off emacs GC has resulting in no noticeable degradation and has eliminated GC pauses. so why not do it?

maybe emacs just doesn't use enough memory, relative to modern systems, for GC to be worth it.

(i do quit emacs at the end of each day, so that is a form of GC.)


The memory consumption of GC languages with GC turned will never decrease, and basically keep increasing unless completely idle. Efficiency has nothing to do with it. conses are generated whether you want it or not, for every single line of Lisp executed.


Not everything in emacs is written in elisp. I can tell you _for sure_ that turning off GC in emacs doesn't result in a runaway train of resident memory.

You can be incorrect, or you can try it.


sure, but if you're not generating enough garbage over the lifetime of the app for it to matter, why waste time collecting? especially is your collector is an old-school design that hangs the app for a user-noticeable amount of time...


this isn't true of all gc languages some (C# and Julia for example) are pretty good at preventing lots of allocations through optimizations.


It is or was a traditional mark-sweep gc, so a very large collection can be slow even if there is not much live data. The gc still has to touch all the garbage to return it to the free lists. Also, Emacs itself might slow down from the terrible cache locality.


> I have 256GB RAM locally so I might as well use it.

But how much swap space do you have?


Do you ever run out of RAM?


Never. I rarely get above 170GB RES. Most days below 30GB, even.


i use the same trick (who w/ only 16GB of ram) -- so far so good.


Wow, can you share some more specs?


It's just a pretty old HP Z820 workstation. Not top of the line by any stretch of the imagination.

Here's an older geekbench report: https://browser.geekbench.com/v5/cpu/3159963


Who actually has issues with gc pauses? I've never noticed them on modern hardware. Are they an issue on embedded systems or something?


See also 'Why are you changing gc-cons-threshold?' <https://bling.github.io/blog/2016/01/18/why-are-you-changing...>


I don't understand the lack of interest in a better garbage collector, rather than pratting about with the limitations of the current one. The port to the Boehm generational, incremental collector many years ago was just ignored.


Concurrent collecting generational collectors are old hat now and Emacs should use them.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: