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

From: Stefan Monnier <[email-masked]>
Date: Wed, 03 Feb 2021 18:32:36 -0500

>> - one `static unsigned long hoard_size` keeps the approximate amount of
>>   space that is free but not returned to the OS.
>>   Not sure where/when to keep it up to date cheaply, admittedly.
> With full atomic access because malloc is multi-threaded; atomics are
> expensive compared to thread-local or nonexisting data.  Updating this
> has to be in the critical path, too.

Indeed, multithreading makes it all much more fun.  I guess you'd want
to make those info thread-local, which would force a rethink of its
definition (what about data allocated in one thread bu freed in another,
yadda, yadda).  The key would be to make sure this is not updated for
every call to `free` but only for some of them (that's why it says
"approximate").

Not having the source code of `free` at hand, I'm free to assume that
this is possible.  E.g. we could say that we don't count objects smaller
than a certain size or for objects smaller than 2^N (for some arbitrary
2^N), you only count it if it's placed at the beginning of the 2^N chunk
(and you count it as having size 2^N)?

>> - one `static unsigned long smallest_recent_hoard_size`.
>>   This is updated whenever we allocate memory from the OS.
> We map huge chunks at a time, but they stay unbacked until they're
> actually used.

By "whenever we allocate memory from the OS" I really meant "in a code
path that's not speed critical but which can be expected to be executed
eventually".  Maybe there isn't any such path except for those that may
never be executed?

>> Then you'd call `malloc_trim` based on a magic formula
> That's cheating ;-)

Like the rest of my hand waving wasn't?
C'mon, give me some credit!

[ Just to clarify: by "magic formula" I meant that this would be the
  part amenable to tuning to decide how often we're willing to pay for
  `malloc_trim`.  ]

>>> Yet another word of memory used,
>> Since 200MB is peanuts, I figure that extra 24B should be acceptable ;-)
> *per chunk*.

No, those counters are meant to be global.  

Anyway.  I see that we should presume that our glibc will not release
our memory back to the OS unless we explicitly ask it to with
`malloc_trim`.  Thanks.

One thing that remains a bit unclear for me is in the doc of
`malloc_trim`; it says:

       The pad argument specifies the amount of free space to leave  untrimmed
       at the top of the heap.  If this argument is 0, only the minimum amount
       of memory is maintained at the top of  the  heap  (i.e.,  one  page  or
       less).   A nonzero argument can be used to maintain some trailing space
       at the top of the heap in order to allow future allocations to be  made
       without having to extend the heap with sbrk(2).

But this only talks about the free space at the "top".  Since in our
case most of the free space is not at the top, I wonder:
say we have 64KB free at the top and 64MB free elsewhere and we call
`malloc_trim` with a `pad` of 16MB, will it release ~48MB of the
non-top free memory or will it free all 64MB of the non-top free memory
or ... ?

        Stefan