madvise
with such flags marks pages as not needed for the application, OS may destroy data from them and unmap physical space;
Ref: link
由於沒有時間細細研究 Understanding glibc malloc
/*
malloc_trim(size_t pad);
If possible, gives memory back to the system (via negative
arguments to sbrk) if there is unused memory at the `high' end of
the malloc pool. You can call this after freeing large blocks of
memory to potentially reduce the system-level memory requirements
of a program. However, it cannot guarantee to reduce memory. Under
some allocation patterns, some large free blocks of memory will be
locked between two used chunks, so they cannot be given back to
the system.
The `pad' argument to malloc_trim represents the amount of free
trailing space to leave untrimmed. If this argument is zero,
only the minimum amount of memory to maintain internal data
structures will be left (one page or less). Non-zero arguments
can be supplied to maintain enough trailing space to service
future expected allocations without having to re-obtain memory
from the system.
Malloc_trim returns 1 if it actually released any memory, else 0.
On systems that do not support "negative sbrks", it will always
return 0.
*/
int
__malloc_trim(size_t s)
{
int result = 0;
if(__malloc_initialized < 0)
ptmalloc_init ();
mstate ar_ptr = &main_arena;
do
{
(void) mutex_lock (&ar_ptr->mutex);
result |= mtrim (ar_ptr, s);
(void) mutex_unlock (&ar_ptr->mutex);
ar_ptr = ar_ptr->next;
}
while (ar_ptr != &main_arena);
return result;
}
/*
------------------------- malloc_consolidate -------------------------
malloc_consolidate is a specialized version of free() that tears
down chunks held in fastbins. Free itself cannot be used for this
purpose since, among other things, it might place chunks back onto
fastbins. So, instead, we need to use a minor variant of the same
code.
Also, because this routine needs to be called the first time through
malloc anyway, it turns out to be the perfect place to trigger
initialization code.
*/
/*
------------------------------ malloc_trim ------------------------------
*/
static int mtrim(mstate av, size_t pad)
{
/* Ensure initialization/consolidation */
malloc_consolidate (av);
const size_t ps = GLRO(dl_pagesize);
int psindex = bin_index (ps);
const size_t psm1 = ps - 1;
int result = 0;
for (int i = 1; i < NBINS; ++i)
if (i == 1 || i >= psindex)
{
mbinptr bin = bin_at (av, i);
for (mchunkptr p = last (bin); p != bin; p = p->bk)
{
INTERNAL_SIZE_T size = chunksize (p);
if (size > psm1 + sizeof (struct malloc_chunk))
{
/* See whether the chunk contains at least one unused page. */
char *paligned_mem = (char *) (((uintptr_t) p
+ sizeof (struct malloc_chunk)
+ psm1) & ~psm1);
assert ((char *) chunk2mem (p) + 4 * SIZE_SZ <= paligned_mem);
assert ((char *) p + size > paligned_mem);
/* This is the size we could potentially free. */
size -= paligned_mem - (char *) p;
if (size > psm1)
{
#ifdef MALLOC_DEBUG
/* When debugging we simulate destroying the memory
content. */
memset (paligned_mem, 0x89, size & ~psm1);
#endif
madvise (paligned_mem, size & ~psm1, MADV_DONTNEED);
result = 1;
}
}
}
}
#ifndef MORECORE_CANNOT_TRIM
return result | (av == &main_arena ? systrim (pad, av) : 0);
#else
return result;
#endif
}