Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/68.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Malloc与定制分配器:Malloc有很多开销。为什么?_C_Memory_Malloc - Fatal编程技术网

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

Malloc与定制分配器:Malloc有很多开销。为什么?,c,memory,malloc,C,Memory,Malloc,我有一个图像压缩应用程序,现在有两个不同版本的内存分配系统。在最初的一个示例中,malloc在任何地方都使用,在第二个示例中,我实现了一个简单的池分配器,它只分配内存块并将部分内存返回给myalloc()调用 在使用malloc时,我们注意到了巨大的内存开销:在内存使用率最高的时候,malloc()代码对于1920x1080x16bpp映像需要大约170兆的内存,而池分配器只分配48兆,其中47兆由程序使用 就内存分配模式而言,程序为测试映像分配大量8字节(most)、32字节(多个)和1080

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

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

就内存分配模式而言,程序为测试映像分配大量8字节(most)、32字节(多个)和1080字节块(一些)。除此之外,代码中没有动态内存分配

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

我们如何测试内存使用情况

使用自定义分配器,我们可以看到使用了多少内存,因为所有malloc调用都延迟到分配器。对于malloc(),在调试模式下,我们只需在任务管理器中浏览代码并查看内存使用情况。在发布模式下,我们也做了同样的事情,但细粒度较低,因为编译器优化了大量内容,所以我们无法逐段地遍历代码(发布和调试之间的内存差异约为20MB,我认为这是由于在发布模式下优化和缺少调试信息)


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

首先,malloc将指针与16字节边界对齐。此外,它们在返回值之前的地址中存储至少一个指针(或分配的长度)。然后,他们可能会添加一个神奇的值或释放计数器,以指示链表没有被破坏,或者内存块没有被释放两次(释放断言用于双重释放)

#包括
#包括
内部主(内部ac,字符**av)
{
int*foo=malloc(4);
int*bar=malloc(4);
printf(“%d\n”,(int)bar-(int)foo);
}

Return:32

警告:在Visual Studio中运行程序或连接任何调试器时,默认情况下malloc行为会发生很大变化,内存开销可能无法代表实际使用情况(另请参阅)。您需要使用环境变量_NO_DEBUG_HEAP=1以避免受到此影响,或者在不在调试器下运行时测量内存使用情况。

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

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


最好的办法就是不要为此烦恼,170MB的容量是微不足道的。请记住,这是虚拟的内存,它不需要任何费用。

通常,您只需要编写一个通用的自定义版本,而您所编写的内容由于了解计划如何使用它的细节,会在性能上增加很多好处。但是,我不希望使用malloc会带来内存开销。你确定你测量的内存使用正确吗?您确定在使用malloc时正确释放了内存吗?malloc代码中的所有内容都被释放(我使用内存分析器对此进行了测试),但仅在应用程序的最末端,在它完成执行之前释放,因此在调用任何free()函数之前(在两个版本中)都会进行测量。自定义分配器加快了整个过程,并为每个映像节省了约15毫秒的时间(因为它只是一个大的分配,而不是很多小的分配)。对于
malloc
来说,200%的开销似乎太大了,除非8字节分配比您想象的多得多。malloc很可能“保留”释放内存以供立即使用后再释放一些内存。如果你的实现使用的是std::vector,你可以提前“保留”,尽管当你要分配这么大的内存时,最好不要选择需要连续缓冲区的模型。你能描述一下你们是如何衡量内存使用率的吗?你的意思是32位占用16字节吗?@Aki he说有很多32字节的分配。为什么你会提出32位的分配?这是在64位ubuntu中测试的。在32位系统中,很可能需要16个字节。@UmNyobe:显然是我的错误。无论如何,8字节malloc需要32字节,32字节malloc至少需要48字节。谢谢。这种排列可能解释了大量的记忆丧失。Aki,你有这些信息的来源吗?“在Windows7上,你总是会得到低碎片堆分配器”,除非你在调试器下运行。根据所描述的方法(单步执行代码),在测量内存消耗时似乎使用了调试器,因此没有使用LFH。请看我的答案。那篇文章引用了古代历史,Vista对内存管理器进行了重大修改。但是是的,堆调试功能使用的块填充会影响他看到的VM使用量。虚拟内存需要花费一些钱,缺页对性能来说是痛苦的。不,访问空闲块不会导致缺页。“那可能是个错误。”汉斯,也许我当时弄错了,你能进一步解释一下吗?
#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);
}