glibc malloc() 使用 mmap() 进行小块内存分配?

glibc malloc() 使用 mmap() 进行小块内存分配?

我了解到,在 Linux 上,glibc 的 malloc() 使用 mmap() 来处理非常大的内存块,而 brk() 用于小分配。然而,当我用测试程序对该理论进行实验时,情况似乎并非如此。

首先,我在代码中使用“for”循环来分配由条件 Option1==TRUE 的数组实现的一大块内存 (80MB),并且每次分配都是页面大小的倍数。当 Option2==TRUE 时,内存块将被完全释放。注意 Option1 和 Option2 可以从我的进程运行的命令行进行设置。

观察结果:当选项 1 满足时,我的进程的 RSS 值增加了 80MB。之后,我将 Option2 设置为 TRUE(而 Option1 不满意),然后从 RSS 值中减少了大约相同数量的内存(返回给操作系统)。到目前为止一切都很好。

之后,我修改了“for”循环来分配大块内存(每个 80MB)由以下实现块1与选项1。在每个循环中,两个数组的相同索引被分配相同数量的内存,并且每次分配都是较小超过一页。内存块为当Option2==TRUE时将被完全释放。和内存块块1当Option3==TRUE时将被完全释放。

观察:当 Option1==TRUE 时,我的进程的 RSS 值增加了 160MB,并且在 Option2==TRUE 后该值保持不变。并且在 Option3==TRUE 之后也保持不变。我使用 Valgrind Massif 工具检查内存使用情况,它报告“for”循环中的两个 malloc() 函数映射了大约 160 MB 的页面。

我可以理解,小分配的内存块保留在进程中,以便它们可以用于将来的分配。但是这些小分配不应该由 brk() 而不是 mmap() 实现吗?是因为 valgrind 没有提供准确的报告,还是因为还有其他一些情况使用 mmap() 来实现 malloc() ?

我的第二个测试的代码复制如下:

        char *chunk[200000];
        char *chunk1[200000];
        int i = 0;
        int j,k;
......
        if (<Option1 == TRUE>) {
            if (i < 100) {
                for (k=0; k<2000; k++) {
                chunk[i*2000+k] = (char *)malloc(400);
                chunk1[i*2000+k] = (char *)malloc(400);
                memset (chunk[i*2000+k], 0, 400);
                memset (chunk1[i*2000+k], 0, 400);
                }
            }
        }
        if (<Option2 == TRUE>) {
            for (j = 0; j < 200000; j++) {
                if (chunk[j] != NULL) {
                    free(chunk[j]);
                    chunk[j] = NULL;
                }
            }
        }
        if (<Option3 == TRUE>) {
            for (j = 0; j < 200000; j++) {
                if (chunk1[j] != NULL) {
                    free(chunk1[j]);
                    chunk1[j] = NULL;
                }
            }
        }
......

答案1

这实际上取决于malloc实施。它可能会预先分配一个更大的连续内存块,然后在其上做一些魔法 - 例如,根据请求的大小从大块的不同部分分配较小的内存块。这么大的块当然可以通过分配mmap

您可以检查例如杰马洛克的来源来了解这是如何工作的。

相关内容