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

From: Konstantin Kharlamov <[email-masked]>
Date: Wed, 03 Feb 2021 00:17:02 +0300

On Tue, 2021-01-26 at 10:30 -0500, Stefan Monnier wrote:
> > That'd be easy to implement, but I'm not yet sure it's the best
> > alternative.  In particular, I'd like to have some idea regarding how
> > much time such a call could take.  In some usage patterns Emacs calls
> > GC very frequently, which slows down command execution and makes Emacs
> > less responsive.
>
> The most important case where this happens is during phases of creation
> of large new structures (e.g. while loading a large package like Org),
> where a lot of memory is allocated without generating much garbage, so
> every time we run the GC that time is mostly wasted (since we don't
> recover any garbage) and calling malloc_trim would also be useless in
> those cases.

So, I just did some benchmarking; the patch I bencharked it with was modified per Stefan's comment (i.e. `malloc_trim(0)` is moved to the end of `garbage_collec()`). I'm attaching it here as well.

Benchamarking was done as follows: I ran built emacs as `src/emacs -Q`; and used this code

    (benchmark-run
        (let ((i 1000000))
          (while (> i 0)
            (print "hello")
            (setq i (- i 1)))))

which I ran 3 times. First with the patch; then I git-checked out HEAD^ (i.e. to the code without my patch), built it, and ran 3 times again.

This code you may recognize, it was the reproducer to show Emacs taking 200M of memory, except I cut out the line disabling GC, and the line that calls GC manually. IOW I used a known memory-heavy testcase, and ran it with vanilla Emacs configuration.

Results are:

    with malloc_trim:
        (8.920371394 232 2.106283245)
        (9.038083601 231 2.060810826)
        (9.140798641 231 2.0594013240000004)

    without malloc_trim:
        (8.987097209 232 2.070143482)
        (8.700478084 231 1.7745506179999997)
        (8.781121056 231 1.7870093610000004)

The difference is just 3-4% (8.7 / 9 ≈ 0.9666666667). It looks to me insignificant enough to not show up anywhere during interactive work with Emacs.

From bc09ce4e25ff2c361d19ace35e556b738651c0a2 Mon Sep 17 00:00:00 2001
From: Konstantin Kharlamov <[email-masked]>
Date: Sun, 24 Jan 2021 17:55:23 +0300
Subject: [PATCH] Force Glibc to free the memory freed

configure.ac: check whether malloc_trim is suported
src/alloc.c (garbage_collect): call malloc_trim() if possible
(bug#45200)
---
 configure.ac | 3 +++
 src/alloc.c  | 3 +++
 2 files changed, 6 insertions(+)

diff --git a/configure.ac b/configure.ac
index 08f3c0cd85..416cfbe389 100644
--- a/configure.ac
+++ b/configure.ac
@@ -4556,6 +4556,9 @@ AC_DEFUN
 dnl the current CFLAGS etc.
 AC_CHECK_FUNCS(snprintf)
 
+
+AC_CHECK_FUNCS(malloc_trim)
+
 dnl Check for glib.  This differs from other library checks in that
 dnl Emacs need not link to glib unless some other library is already
 dnl linking to glib.  Although glib provides no facilities that Emacs
diff --git a/src/alloc.c b/src/alloc.c
index b86ed4ed26..3124378fb8 100644
--- a/src/alloc.c
+++ b/src/alloc.c
@@ -6146,6 +6146,9 @@ garbage_collect (void)
       if (tot_after < tot_before)
 	malloc_probe (min (tot_before - tot_after, SIZE_MAX));
     }
+#ifdef HAVE_MALLOC_TRIM
+  malloc_trim(0); /* work around for high memory consumption, see bug 45200 */
+#endif /* HAVE_MALLOC_TRIM */
 }
 
 DEFUN ("garbage-collect", Fgarbage_collect, Sgarbage_collect, 0, 0, "",
-- 
2.30.0