了解格列布克马洛克修剪



我目前正在处理的某些程序消耗的内存比我认为的要多得多。所以我试图了解格利布马洛克修剪是如何工作的。我写了以下测试:

#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=%dn", ret);
    malloc_stats();
    sleep(100000);
}

测试输出(不调用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

尽管几乎所有内存都已释放,但此测试代码消耗的驻留内存比预期的要多得多:

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

流程图:

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测试的输出几乎保持不变时:

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

流程图(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后,堆被回避了。我假设 8MB mmap 段仍然可用,因为最后一块内存没有发布。

为什么堆修整不是由 malloc 自动执行的?有没有办法配置 malloc 以便自动完成修剪(当它可以节省那么多内存时(?

我正在使用 glibc 版本 2.17。

主要是由于历史原因,小分配的内存来自使用 brk 系统调用管理的池。 这是一个非常古老的系统调用 - 至少与版本6 Unix一样旧 - 它唯一能做的就是更改内存中位置固定的"竞技场"的大小。 这意味着,brk池不能收缩超过仍在分配的块。

程序分配 N 个内存块,然后解除分配其中的 N-1 个。 它不释放的一个块是位于最高地址的块。 这是brk最糟糕的情况:即使池的 99.99% 未使用,大小根本无法减小! 如果您更改程序,使其不释放的块array[0]而不是array[NUM_CHUNKS-1],您应该看到 RSS 和地址空间在最后一次调用 free 时都缩小了。

当您显式调用 malloc_trim 时,它会尝试使用 Linux 扩展 madvise(MADV_DONTNEED) 来解决此限制,这会释放物理 RAM,但不释放地址空间(如您所观察到的(。 我不知道为什么这只发生在明确呼吁malloc_trim.

顺便说一下,8MB mmap 段用于您初始分配 array .

最新更新