了解glibc malloc修剪

我目前正在做的一些程序比我想象的要消耗更多的内存。 所以我想了解如何glibc malloc修剪工作。 我写了下面的testing:

#include <malloc.h> #include <unistd.h> #define NUM_CHUNKS 1000000 #define CHUNCK_SIZE 100 int main() { // disable fast bins mallopt(M_MXFAST, 0); void** array = (void**)malloc(sizeof(void*) * NUM_CHUNKS); // allocating memory for(unsigned int i = 0; i < NUM_CHUNKS; i++) { array[i] = malloc(CHUNCK_SIZE); } // releasing memory ALMOST all memory for(unsigned int i = 0; i < NUM_CHUNKS - 1 ; i++) { free(array[i]); } // when enabled memory consumption reduces //int ret = malloc_trim(0); //printf("ret=%d\n", ret); malloc_stats(); sleep(100000); } 

testing输出(不调用malloc_trim):

 Arena 0: system bytes = 112054272 in use bytes = 112 Total (incl. mmap): system bytes = 120057856 in use bytes = 8003696 max mmap regions = 1 max mmap bytes = 8003584 

尽pipe几乎所有的内存都被释放了,但是这个testing代码比预期的消耗更多的内存:

 [root@node0-b3]# ps aux | grep test root 14662 1.8 0.4 129736 **118024** pts/10 S 20:19 0:00 ./test 

stream程smaps:

 0245e000-08f3b000 rw-p 00000000 00:00 0 [heap] Size: 109428 kB Rss: 109376 kB Pss: 109376 kB Shared_Clean: 0 kB Shared_Dirty: 0 kB Private_Clean: 0 kB Private_Dirty: 109376 kB Referenced: 109376 kB Anonymous: 109376 kB AnonHugePages: 0 kB Swap: 0 kB KernelPageSize: 4 kB MMUPageSize: 4 kB Locked: 0 kB VmFlags: rd wr mr mw me ac 7f1c60720000-7f1c60ec2000 rw-p 00000000 00:00 0 Size: 7816 kB Rss: 7816 kB Pss: 7816 kB Shared_Clean: 0 kB Shared_Dirty: 0 kB Private_Clean: 0 kB Private_Dirty: 7816 kB Referenced: 7816 kB Anonymous: 7816 kB AnonHugePages: 0 kB Swap: 0 kB KernelPageSize: 4 kB MMUPageSize: 4 kB Locked: 0 kB 

当我启用对malloc_trim的调用时,testing的输出保持几乎相同:

 ret=1 Arena 0: system bytes = 112001024 in use bytes = 112 Total (incl. mmap): system bytes = 120004608 in use bytes = 8003696 max mmap regions = 1 max mmap bytes = 8003584 

但是,RSS显着下降:

 [root@node0-b3]# ps aux | grep test root 15733 0.6 0.0 129688 **8804** pts/10 S 20:20 0:00 ./test 

进程smaps(在malloc_trim之后):

 01698000-08168000 rw-p 00000000 00:00 0 [heap] Size: 109376 kB Rss: 8 kB Pss: 8 kB Shared_Clean: 0 kB Shared_Dirty: 0 kB Private_Clean: 0 kB Private_Dirty: 8 kB Referenced: 8 kB Anonymous: 8 kB AnonHugePages: 0 kB Swap: 0 kB KernelPageSize: 4 kB MMUPageSize: 4 kB Locked: 0 kB VmFlags: rd wr mr mw me ac 7f508122a000-7f50819cc000 rw-p 00000000 00:00 0 Size: 7816 kB Rss: 7816 kB Pss: 7816 kB Shared_Clean: 0 kB Shared_Dirty: 0 kB Private_Clean: 0 kB Private_Dirty: 7816 kB Referenced: 7816 kB Anonymous: 7816 kB AnonHugePages: 0 kB Swap: 0 kB KernelPageSize: 4 kB MMUPageSize: 4 kB Locked: 0 kB 

在调用malloc_trim之后,堆被分stream了。 我认为8MB的mmap片段仍然可用,因为最后一块没有发布的内存。

为什么堆整理不是由malloc自动执行的? 有没有办法configurationmalloc,以便自动修剪(当它可以节省大量的内存)?

我正在使用glibc版本2.17。

很大程度上是由于历史原因,小分配的内存来自用brk系统调用管理的池。 这是一个非常古老的系统调用 – 至少和第六版Unix一样古老 – 它唯一能做的就是改变内存中固定位置的“竞技场” 的大小 。 这意味着, brk池不能缩小仍然分配的块。

你的程序分配N个内存块,然后释放N-1个内存。 它不会释放的块是位于最高地址的块。 这是brk的最坏情况:即使99.99%的游戏池未被使用,大小也不能被减少! 如果你改变你的程序,使它不空闲的块是array[0]而不是array[NUM_CHUNKS-1] ,你应该看到RSS和地址空间在最后一次free缩小。

在显式调用malloc_trim ,它会尝试使用Linux扩展madvise(MADV_DONTNEED)来解决此限制,该扩展会释放物理RAM,但不会释放地址空间(如您madvise(MADV_DONTNEED) )。 我不知道为什么这只发生在显式调用malloc_trim

顺便说一下,8MB的mmap段是为你的初始array分配。