为什么malloc会消耗那么多内存?

为什么malloc会消耗那么多内存?,c,malloc,C,Malloc,我有一个项目,我做了很多马洛克的。我发现内存使用量远远大于数据本身。如果我使用valgrind并放入100 MB数据,则分配的内存为500 MB。数据块大小不同,每个大小为20-40字节。这里有一些最小的程序可以做类似的事情,但是块大小相同 它分配了大约43 MB的空间,但瓦尔格兰地块显示为53 MB 如果使用jemalloc运行,top也会显示47MB 目前所有的块大小都不一样,我不能使用数组之类的东西 我是否可以使用malloc的一些设置,或者是否可以使用不同的类似malloc的命令来最小化

我有一个项目,我做了很多马洛克的。我发现内存使用量远远大于数据本身。如果我使用valgrind并放入100 MB数据,则分配的内存为500 MB。数据块大小不同,每个大小为20-40字节。这里有一些最小的程序可以做类似的事情,但是块大小相同

它分配了大约43 MB的空间,但瓦尔格兰地块显示为53 MB

如果使用jemalloc运行,top也会显示47MB

目前所有的块大小都不一样,我不能使用数组之类的东西

我是否可以使用malloc的一些设置,或者是否可以使用不同的类似malloc的命令来最小化浪费的内存

#include <stdlib.h>
#include <string.h>
#include <stdio.h>

#define BUFFER_SIZE 39
#define MANY        1000000LU

typedef struct _list{
    void    *next;
    char    payload[BUFFER_SIZE];
}list;


int main(){
    list root;

    printf("Allocating %lu chunks %zu bytes each, equals to %lu bytes\n", MANY, sizeof(list), MANY * sizeof(list));

    list *node = & root;
    unsigned long int i;
    for(i = 0; i < MANY; i++){
        node->next = malloc(sizeof(list));

        if (node->next == NULL){
            printf("Out of memory\n");
            return 1;
        }

        memset(node->payload, 0, BUFFER_SIZE);

        node = node->next;
    }

    printf("done\n");

    return 0;
}
#包括
#包括
#包括
#定义缓冲区大小39
#定义多个LU
类型定义结构列表{
作废*下一步;
字符负载[缓冲区大小];
}名单;
int main(){
列表根;
printf(“分配%lu个块,每个块%zu个字节,等于%lu个字节\n”),MANY,sizeof(列表),MANY*sizeof(列表));
列表*节点=&root;
无符号长整数i;
对于(i=0;inext=malloc(sizeof(list));
如果(节点->下一步==NULL){
printf(“内存不足\n”);
返回1;
}
memset(节点->有效负载,0,缓冲区大小);
节点=节点->下一步;
}
printf(“完成”\n);
返回0;
}

首先是开销。
malloc
结构中有一小部分开销。我认为它大约是每个
malloc
8个字节。另外(部分是为了对齐,部分是为了实用,部分是为了最小化下面的影响),内存分配的大小将被四舍五入到2的小幂的倍数


第二,碎片化。假设您分配了3900字节的块A、B和C,分配器选择按顺序分配它们。接下来,假设B被释放。由于漏洞小于操作系统页面大小,因此无法将B所在的“漏洞”返回给操作系统。如果使用
malloc
的所有后续分配都大于900字节,则该漏洞将永远不会被填补,即其被浪费。如果(比如)出现了一个600字节的分配,它可能会被放入这个洞中,但这会留下一个300字节的洞。在这种情况下,没有一个分配器能够完美地运行。

在现代操作系统上,
malloc
的常见实现将请求大量虚拟内存空间,并将其拆分为分配池。然后,它将根据自己的优化参数(无论是大小、线程、片段缩减等)从这些池中分发内存。一个天真的记忆观认为这是浪费。但是,虚拟内存在投入使用之前不一定由物理页支持,此时操作系统将根据需要为其回填映射(类似于分页的工作方式,但使用匿名内存支持)。因此,您认为进程正在使用的数字不一定是正在消耗的实际内存,而只是分配给等待使用的VM空间。

malloc从操作系统请求内存。操作系统将整个过程一次映射到进程的虚拟空间。因为你分配的是小块,我想这就是区别的来源。你可以一次分配多个“块”,这样你的一些指针就在分配的块中。当你需要释放物品时,跟踪物品变得更加棘手。我无法复制它。我试着用几个不同的
值运行你的程序,它的开销总是相当小。您能展示一些允许复制它的代码吗?大多数分配器将字节数取整为16的倍数。20字节->32字节,33字节->48字节,48字节->48字节。如何处理?我不认为我会比gnu或facebook的人做得更好,我不确定,你可以,但如果你认为你不能,也许你是对的。这实际上取决于为什么?你想这样做吗。这不是做得更好的问题,而是做正确的工作,适合你的需要。代码中没有反分配,只有malloc(),我明天会对数据进行分析,并将结果发布在这里。你很确定
printf
stdio
缓冲从不分配(或免费)内部有内存吗?printf()不确定,但fopen()肯定有。但是,与其他用法相比,“漏洞”应该很小。
printf()
仅在
malloc()
失败时才在循环中。我完成了以下文件并使用它运行了测试。似乎所有额外的空间都是开销。我还按大小分析了数据的“片段”,发现有很多“非对齐”片段,例如17字节长——在x86_64上,这将“舍入”到32字节,而在Arm上,它将舍入到24字节。最后我尝试了Doug Lea malloc,它给了我令人惊讶的好结果。看来我还是需要找到或者做一个定制的分配器:)我认为内存浪费了,因为我有一个大约500 MB数据的文件。我无法将它加载到带有6GB空闲RAM(英特尔i5)的机器上。@Nick,但你提到了ARM。要清楚,哪个平台,什么问题。