Subject: bug#45200: [PATCH] Force Glibc to free the memory freed

From: Stefan Monnier <[email-masked]>
Date: Wed, 03 Feb 2021 15:24:23 -0500

DJ Delorie [2021-02-03 14:25:15] wrote:
> Right, glibc's malloc maintains a cache of re-usable chunks of memory,
> for performance reasons.

Right, so far as good.

> We (glibc devs) don't consider "poor cache performance for my
> application" to be a bug.  A patch which improves cache performance *for
> most apps* would be considered, but a patch that improves one app's
> speed at the cost of most other apps, would be rejected.

I understand that as well.  But I'm wondering why glibc is willing to
keep *indefinitely* an unused 200MB of memory, which is more than double
the mount of memory in use for the rest of the application's life.

I mean I understand that you can't predict the future, but I expected
that "at some point" glibc should decide that those 200MB have been left
unused for long enough that they deserve to be returned to the OS.
The doc of `malloc_trim` suggests it's occasionally called by `free` and
`mallopt` suggests via `M_TRIM_THRESHOLD` that there's a limit to how
much extra spare memory glibc keeps around, so this suggests that indeed
memory is trimmed "every once in a while".

So what causes Emacs's experience to be different?
If I read `mallopt`s man page carefully I see it say:

       M_TRIM_THRESHOLD
              When the amount of contiguous free memory at the top of the heap
              grows  sufficiently  large,  free(3)  employs sbrk(2) to release
              this memory back to the system.  (This can be useful in programs

so my guess is that in Emacs's case those 200MB of extra memory are
*not* contiguous?  Would that be it?

If so, it does seem like a weakness of glibc's heuristic.

Is there a way for Emacs to ask malloc how much memory (or some
approximation of it) would be recovered by `malloc_trim`?

> You (emacs devs) need to decide whether you care more about memory
> footprint or memory performance, and tune malloc accordingly.
> malloc_trim() is one knob to tune, there are others.  But don't say it's
> a "bug" if our defaults don't match your optimal settings.

In our normal use, glibc's tuning works fine.  We're just seeing some
corner case behaviors which seem clearly undesirable, so I think it
would make sense to try and arrange for glibc to handle them better.

I suspect the issue is how to make it so the malloc library can keep
track of the size of the "cache" without slowing down the most common
execution path.  Once that is done, it should be easy to check the size
of the "cache" every once in a while (e.g. when requesting more memory
from the OS) and call malloc_trim when that cache is "way too big".
Tho of course, "way too big" might just mean we're just about to
re-allocate it, so we'd probably want to include some notion of time so
we only call `malloc_trim` if it's been "way too big" for a while.

        Stefan