public inbox for libc-help@sourceware.org
 help / color / mirror / Atom feed
From: Konstantin Kharlamov <hi-angel@yandex.ru>
To: libc-help@sourceware.org
Subject: `free` fails to reclaim memory
Date: Sun, 13 Dec 2020 14:41:06 +0300	[thread overview]
Message-ID: <3142ea6128492d89e81c58a3d0f2450f1a583f53.camel@yandex.ru> (raw)
In-Reply-To: <E1koKKT-0007bp-7N@fencepost.gnu.org>

Hello, while researching Emacs "leaking memory"¹, we may have actually stumbled upon glibc problem: glibc may not return freed memory to the OS, and by "memory" I mean here not a few kilobytes or megabytes for the sake of cache, but megabytes or even gigabytes. Having researched for a bit, I got the following testcase:

    // credits to https://stackoverflow.com/a/48652734/2388257#glibc-application-holding-onto-unused-memory-until-just-before-exit
    #include <cstdlib>
    #include <cstdio>
    #include <unistd.h>

    int main() {
        static const int N = 50000;
        static void *arr[N];

        for (int i = 0; i < N; i++)
            arr[i] = std::malloc(1024);

        // reverse to simplify allocators job
        for (int i = N - 1; i >= 0; i--)
            std::free(arr[i]);
        puts("Measure");
        sleep(1e5);
    }

This code allocates 50M of memory, and then frees it back. When it goes to sleep, measuring memory with `smem -kc "name pid pss" | grep -P "\ba\b"` will give 50M, despite that memory was freed. Original snippet was allocating 5G, none of which would return to the system as well. This is on glibc 2.32

The stackoverflow answer recommends calling `malloc_trim` for memory to return, but it is an odd recommendation because you can't expect everyone to do workarounds for glibc-specific problems.

Is there any chance this is not an intended behavior, but an actual glibc bug?

1: https://debbugs.gnu.org/cgi/bugreport.cgi?bug=45200

On Sun, 2020-12-13 at 00:53 -0500, Eli Zaretskii wrote:
> > From: Konstantin Kharlamov <hi-angel@yandex.ru>
> > Cc: 45200@debbugs.gnu.org
> > Date: Sun, 13 Dec 2020 01:44:13 +0300
> >
> > Alright, fair enough. I crafted up another testcase, it may be better. The
> > following code first temporarily disables GC, then it prints "hello" 1000000
> > times, and finally it calls GC manually.
> >
> > I call `emacs -Q`, then measure PSS, then evaluate the code below, then
> > again measure PSS.
> >
> >     (let ((i 1000000))
> >       (setq gc-cons-threshold most-positive-fixnum)
> >       (while (> i 0)
> >         (print "hello")
> >         (setq i (- i 1)))
> >       (garbage-collect))
> >
> > The loop takes 20-30 seconds for me, I think. PSS before is ≈41M, and PSS
> > after is 266.3M. That is ≈200M of memory just vanished.
>
> That memory hasn't vanished, it is in your libc's malloc arena,
> available for future allocations.  When and if it will be given back
> to the OS is up to the specifics of the malloc implementation.  E.g.,
> when I do the above on MS-Windows, where malloc is more eager to return
> memory to the OS, I end up with just 40 MB footprint, and if I then
> invoke GC manually, the memory goes down almost to the original value:
> 14 MB vs 12 MB after startup.
>
> There are many places on the Internet which explain why the memory
> footprint of a program doesn't go back to the original value even
> though the program frees all the heap memory it allocated.  I suggest
> to read some of those explanations.



       reply	other threads:[~2020-12-13 11:41 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <dd4a240ab3ff14d8f04d02b2504611a4d9f3f816.camel@yandex.ru>
     [not found] ` <83k0tmeq6f.fsf@gnu.org>
     [not found]   ` <9f49e5542f303736d2e53ce3dc53c1374969e6b4.camel@yandex.ru>
     [not found]     ` <E1koKKT-0007bp-7N@fencepost.gnu.org>
2020-12-13 11:41       ` Konstantin Kharlamov [this message]
2020-12-13 11:57         ` tomas
2020-12-13 12:14           ` Konstantin Kharlamov
2020-12-13 12:32             ` tomas
2020-12-21 22:59               ` Konstantin Kharlamov
2020-12-13 12:33           ` Konstantin Kharlamov
2020-12-13 12:42             ` tomas
2020-12-21 23:18               ` Konstantin Kharlamov

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=3142ea6128492d89e81c58a3d0f2450f1a583f53.camel@yandex.ru \
    --to=hi-angel@yandex.ru \
    --cc=libc-help@sourceware.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).