手册页在malloc_trim
这里提交:https ://github.com/mkerrisk/man-pages/blob/master/man3/malloc_trim.3据我了解,它是由手册页项目维护者 kerrisk 在 2012 年从头开始编写的:https ://github.com/mkerrisk/man-pages/commit/a15b0e60b297e29c825b7417582a33e6ca26bf65
因为我可以grep glibc 的 git,所以 glibc 中没有手册页,也没有提交到 malloc_trim 手册页来记录这个补丁。glibc malloc 最好也是唯一的文档是它的源代码:https ://sourceware.org/git/?p=glibc.git;a=blob;f=malloc/malloc.c
有malloc_trim
评论来自malloc/malloc.c
:
Additional functions:
malloc_trim(size_t pad);
609 /*
610 malloc_trim(size_t pad);
611
612 If possible, gives memory back to the system (via negative
613 arguments to sbrk) if there is unused memory at the `high' end of
614 the malloc pool. You can call this after freeing large blocks of
615 memory to potentially reduce the system-level memory requirements
616 of a program. However, it cannot guarantee to reduce memory. Under
617 some allocation patterns, some large free blocks of memory will be
618 locked between two used chunks, so they cannot be given back to
619 the system.
620
621 The `pad' argument to malloc_trim represents the amount of free
622 trailing space to leave untrimmed. If this argument is zero,
623 only the minimum amount of memory to maintain internal data
624 structures will be left (one page or less). Non-zero arguments
625 can be supplied to maintain enough trailing space to service
626 future expected allocations without having to re-obtain memory
627 from the system.
628
629 Malloc_trim returns 1 if it actually released any memory, else 0.
630 On systems that do not support "negative sbrks", it will always
631 return 0.
632 */
633 int __malloc_trim(size_t);
634
从块的中间释放没有记录为 malloc/malloc.c 中的文本,也没有记录在手册页项目中。2012 年的手册页可能是该函数的第一个手册页,不是由 glibc 的作者编写的。glibc 的信息页面仅提及 128 KB 的 M_TRIM_THRESHOLD:
https : //www.gnu.org/software/libc/manual/html_node/Malloc-Tunable-Parameters.html#Malloc-Tunable-Parameters 并且不列出 malloc_trim 函数https ://www.gnu.org/software/libc/manual/html_node/Summary-of-Malloc.html#Summary-of-Malloc(它也没有记录 memusage/memusagestat/libmemusage.so)。
2007 年 12 月,Ulrich Drepper 提交了https://sourceware.org/git/?p=glibc.git;a=commit;f=malloc/malloc.c;h=68631c8eb92ff38d9da1ae34f6aa048539b199cc(它是 glibc 2.9 和更新版本的一部分) ) 更改了mtrim
实现(但它没有更改任何文档或手册页,因为 glibc 中没有手册页):
- malloc/malloc.c (public_mTRIm): 遍历所有 arenas 并调用
所有人的 mTRIm。(mTRIm):另外遍历所有空闲块并使用 madvise 为所有包含至少一个内存页的块释放内存。
块的未使用部分(任何地方,包括中间的块),在页面大小上对齐并且大小超过页面可以标记为MADV_DONTNEED
https://sourceware.org/git/?p=glibc.git;a=blobdiff;f =malloc/malloc.c;h=c54c203cbf1f024e72493546221305b4fd5729b7;hp=1e716089a2b976d120c304ad75dd95c63737ad75;hb=68631c8eb92ff38d9da1ae34f6aa048539b199cc;hpb=52386be756e113f20502f181d780aecc38cbb66a
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)
madvise (paligned_mem, size & ~psm1, MADV_DONTNEED);
}
madvise
这是现在 glibc 中with的两种用法之一MADV_DONTNEED
,一种用于堆的顶部(shrink_heap
),另一种是标记任何块(mtrim
):http ://code.metager.de/source/search?q=MADV_DONTNEED&path=% 2Fgnu%2Fglibc%2Fmalloc%2F&project=gnu
H A D arena.c 643 __madvise ((char *) h + new_size, diff, MADV_DONTNEED);
H A D malloc.c 4535 __madvise (paligned_mem, size & ~psm1, MADV_DONTNEED);
我们可以malloc_trim
用这个简单的 C 程序 ( test_malloc_trim.c
) 和strace
/来测试ltrace
:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <malloc.h>
int main()
{
int *m1,*m2,*m3,*m4;
printf("%s\n","Test started");
m1=(int*)malloc(20000);
m2=(int*)malloc(40000);
m3=(int*)malloc(80000);
m4=(int*)malloc(10000);
// check that all arrays are allocated on the heap and not with mmap
printf("1:%p 2:%p 3:%p 4:%p\n", m1, m2, m3, m4);
// free 40000 bytes in the middle
free(m2);
// call trim (same result with 2000 or 2000000 argument)
malloc_trim(0);
// call some syscall to find this point in the strace output
sleep(1);
free(m1);
free(m3);
free(m4);
// malloc_stats(); malloc_info(0, stdout);
return 0;
}
gcc test_malloc_trim.c -o test_malloc_trim
,strace ./test_malloc_trim
write(1, "Test started\n", 13Test started
) = 13
brk(0) = 0xcca000
brk(0xcef000) = 0xcef000
write(1, "1:0xcca010 2:0xccee40 3:0xcd8a90"..., 441:0xcca010 2:0xccee40 3:0xcd8a90 4:0xcec320
) = 44
madvise(0xccf000, 36864, MADV_DONTNEED) = 0
...
nanosleep({1, 0}, 0x7ffffafbfff0) = 0
brk(0xceb000) = 0xceb000
因此,调用后madvise
有MADV_DONTNEED
9 页malloc_trim(0)
,此时堆中间有 40008 字节的空洞。