当前位置: 首页 > 知识库问答 >
问题:

Malloc与自定义分配器:Malloc有很多开销。为什么?

羊舌新荣
2023-03-14

我有一个图像压缩应用程序,现在有两个不同版本的内存分配系统。在最初的一个例子中,malloc无处不在,在第二个例子中,我实现了一个简单的池分配器,它只分配大块内存,并将部分内存返回给myalloc()调用。

我们注意到,使用malloc时会产生巨大的内存开销:在内存使用量最大的时候,malloc()代码对于1920x1080x16bpp映像需要大约170 MB的内存,而池分配器只分配48 MB,其中47 MB由程序使用。

在内存分配模式方面,程序用测试镜像分配了很多8字节(大部分)、32字节(很多)和1080字节块(一些)。除此之外,代码中没有动态内存分配。

测试系统的操作系统是Windows 7(64位)。

我们如何测试内存使用率?

使用自定义分配器,我们可以看到使用了多少内存,因为所有malloc调用都被分配器击败。使用malloc(),在调试html" target="_blank">模式下,我们只是逐步完成代码并观察任务管理器中的内存使用情况。在发布模式下,我们做了同样的事情,但没有那么细粒度,因为编译器优化了很多东西,所以我们无法逐段遍历代码(发布和调试之间的内存差异约为20MB,我将其归因于优化和发布模式下缺乏调试信息)。

难道只有malloc才是如此巨大开销的原因吗?如果是这样,是什么导致了malloc内部的这种开销?

共有3个答案

胥承
2023-03-14

警告:在Visual Studio中运行程序或连接任何调试器时,默认情况下malloc行为会发生很大变化,不会使用低碎片堆,并且内存开销可能无法代表实际使用情况(另请参阅)https://stackoverflow.com/a/3768820/16673). 您需要使用环境变量\u NO\u DEBUG\u HEAP=1,以避免受到此影响,或者测量不在调试器下运行时的内存使用情况。

韩烈
2023-03-14

首先malloc将指针对齐到16字节边界。此外,它们在返回值之前的地址中存储至少一个指针(或分配的长度)。然后他们可能会添加一个魔法值或释放计数器来指示链表没有损坏或内存块没有被释放两次(双重释放的免费ASSERTS)。

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

int main(int ac, char**av)
{
  int *foo = malloc(4);
  int *bar = malloc(4);
  printf("%d\n", (int)bar - (int)foo);
}

返回:32

郎河
2023-03-14

在Windows 7上,您将始终获得低碎片堆分配器,而无需显式调用HeapSetInformation()来请求它。该分配器牺牲虚拟内存空间以减少碎片。你的程序实际上并没有使用170兆字节,你只是看到周围有一堆空闲的块,等待类似大小的分配。

这个算法很容易用一个不做任何减少碎片的自定义分配器来击败。这很可能适合您,尽管在您保持程序运行时间超过单个调试会话之前,您不会看到它的副作用。如果这是预期的使用模式,您确实需要确保它在几天或几周内保持稳定。

最好的办法就是不要为此而烦恼,170MB是个小问题。请记住,这是虚拟内存,不需要任何成本。

 类似资料:
  • malloc(配置内存空间) 相关函数 calloc,free,realloc,brk 表头文件 #include<stdlib.h> 定义函数 void * malloc(size_t size); 函数说明 malloc()用来配置内存空间,其大小由指定的size决定。 返回值 若配置成功则返回一指针,失败则返回NULL。 范例 void p = malloc(1024); /*配置1k的内存

  • malloc 配置内存空间 相关函数 calloc,free,realloc,brk 表头文件 #include<stdlib.h> 定义函数 void *malloc(size_t size); 函数说明 malloc()用来配置内存空间,其大小由指定的size决定。 返回值 若配置成功则返回一指针,失败则返回NULL。 范例 void p = malloc(1024); /*配置1k的内存

  • 问题内容: 我知道这可能是一个愚蠢的问题,但是我已经寻找了一段时间,找不到确切的答案。如果我使用或(在Linux机器上的C语言中),是否有人在RAM中分配空间?例如,如果我有2GB的RAM并想使用所有可用的RAM,我可以只使用组合键,还是还有我不知道的另一种选择? 我想编写一系列简单的程序,这些程序可以同时运行,并保留进程中使用的所有RAM来强制使用交换,并且频繁交换页面。我已经在下面的程序中尝试

  • 问题内容: 什么回报? 答案会一样吗? Linux GCC的输出: 输出每次都会保持变化。这是标准答案吗?为什么除了学术研究之外,还有谁会对获得这样的指示感兴趣? 编辑: 如果返回伪指针,则以下内容如何工作: 编辑: 以下代码为每次迭代输出“可能”。为什么不失败? 问题答案: 其他人已经回答了如何工作。我将回答您提出的尚未回答的问题之一(我认为)。问题是关于: 什么回报?答案会一样吗? 该标准规定

  • 我发现malloc()分配的内存空间比我要求的要多。 正如前面提到的代码一样,实际上为每个函数调用分配了32个字节(由top计算),但valgrind实际上只显示了每个调用16个字节。 为什么malloc分配的内存空间比我要求的要多,以及如何强制不要浪费那么多内存空间? 令人惊讶的是,即使结构为24字节,它也分配32字节,所以我猜内存空间被浪费了。我不确定是否应该分配32字节的倍数。如果是真的,那

  • 我不得不问:从逻辑上讲,为什么地址边界本身在什么上可分很重要?使用地址上的整数将一组内存分配给的调优有什么问题? 我知道指针算术是如何工作的,但我无法计算边界的重要性······