我有一个多线程的部分,其中线程需要分配几个大的数据段,每个段大约100MB,作为缓冲区。此外,可能需要在运行时多次调整缓冲区的大小。
自然的解决方案是使用realloc,但它可能会移动不需要的内存。调整缓冲区大小的free/malloc对恐怕会导致碎片,提前预留内存会产生其他问题。
我可以使用什么来分配/重新分配内存?
发布于 2012-05-22 07:48:11
使用free和malloc。这不会导致碎片问题。
现代分配器对内存碎片的抵抗力相当强。如今,需要一个相当病态的程序才能导致碎片问题。当我们的程序直接寻址物理RAM时,碎片是一个更严重的问题,但是使用虚拟内存,程序堆中的一个大“洞”不需要消耗任何资源。
此外,由于缓冲区的大小,大多数分配器将为每个缓冲区从内核请求一个专用区域。在Linux / OS / BSD上,这意味着每个缓冲区的幕后都有一个匿名mmap。这可能会导致地址空间的碎片,但虚拟地址空间在64位系统上基本上是空闲的,在32位系统上几百兆也不是问题。
所以使用free和malloc。
替代方法:你可能会发现让每个缓冲区比你需要的更大会更快。就像malloc在现代Unix上的工作方式一样,任何你不写的页面都不会消耗内存。
所以,如果你malloc一个500MB的缓冲区,但只使用前100MB,你的程序实际上并不会比你malloc一个100MB的缓冲区使用更多的内存。这样可以获得更多的地址空间碎片,但这在64位系统上不是问题,而且您总是可以调整分配大小,以便它也能在32位系统上工作。
至于使用mmap的建议,只需将malloc/free看作是mmap/munmap的一个更简单的接口,这就是它对于大分配的情况(1 MiB是一个常见的阈值)。
发布于 2012-05-22 10:16:24
只需使用realloc即可。在现代系统上,即使缓冲区被移动到一个新地址,移动也是通过操作页表(在Linux、mremap上;我相信其他系统也有类似的机制)而不是通过复制数据来实现的。(请注意,这里我假设的是大缓冲区;对于小缓冲区,通常小于几百kb,将发生实际复制。)
如果您的目标是64位计算机,则完全不需要担心内存碎片。内存碎片永远不会严重到耗尽虚拟地址空间。如果你也需要处理32位机器,只要你没有太多的线程,你可能是安全的。只要总内存消耗小于1 1GB,就很难由于碎片而耗尽虚拟地址空间,假设您的使用模式。如果你担心这个问题,只要预先分配你可能需要的最大大小即可。
发布于 2012-05-22 07:41:19
使用malloc/realloc/free实施您的解决方案,并对其进行分析。如果内存分配有问题,你可以使用更好的malloc实现,比如facebook的jemalloc或者google的tcmalloc。
有关这两者的比较,请参阅C++ memory allocation mechanism performance comparison (tcmalloc vs. jemalloc)。
它们都非常擅长处理内部/外部碎片。
https://stackoverflow.com/questions/10693753
复制相似问题