6

我有多线程部分,其中线程需要分配几个大数据段,例如每个约 100MB,以用作缓冲区。此外,缓冲区可能需要在运行时多次调整大小。

自然的解决方案是使用realloc,但它可能会移动不需要的内存。 free/malloc配对以调整缓冲区大小恐怕会导致碎片和保留内存,然后再产生其他问题。

我可以使用什么来分配/重新分配内存?

4

3 回答 3

5

使用freemalloc。这不会导致碎片问题。

现代分配器对内存碎片具有相当的抵抗力。如今,需要一个相当病态的程序才能导致碎片问题。当我们的程序直接处理物理 RAM 时,碎片化是一个更严重的问题,但是对于虚拟内存,程序堆中的一个大“洞”不需要消耗任何资源。

此外,由于缓冲区的大小,大多数分配器将为每个缓冲区从内核请求一个专用区域。在 Linux / OS X / BSD 上,这意味着每个缓冲区mmap的幕后匿名。 这会导致地址空间的碎片化,但虚拟地址空间在 64 位系统上基本上是免费的,几百兆在 32 位上也不是问题。

所以使用freeand malloc

备选方案:您可能会发现使每个缓冲区比您需要的大更快。这种方式malloc适用于现代 Unix,任何你不写的页面都不会消耗内存。

因此,如果您malloc使用 500 MB 缓冲区但只使用前 100 MB,那么您的程序实际上并不会比使用malloc100 MB 缓冲区并使用整个程序时使用更多的内存。通过这种方式可以获得更多的地址空间碎片,但这在 64 位系统上不是问题,并且您始终可以调整分配大小,使其也适用于 32 位系统。

至于使用的建议mmap,只需将malloc/视为/free的更简单接口,这就是大型分配的含义(1 MiB 是一个常见的阈值)。mmapmunmap

于 2012-05-21T23:48:10.853 回答
4

只需使用realloc. 在现代系统上,即使缓冲区被移动到新地址,移动也将通过操作页表(在 Linux 上,mremap我确信其他系统具有类似的机制)而不是通过复制数据来实现。(请注意,我假设缓冲区很大;对于通常小于几百 kb 的小缓冲区,将发生实际复制。)

If your target is 64-bit machines, there's absolutely no need to worry about memory fragmentation. You'll never fragment memory badly enough to run out of virtual address space. If you need to handle 32-bit machines too, you're probably safe as long as you don't have too many threads. As long as the total memory consumption is less than 1GB, it would be very hard to run out of virtual address space due to fragmentation, assuming your usage pattern. If you are worried about it, just preallocate the largest size you might possibly need.

于 2012-05-22T02:16:24.383 回答
1

使用 malloc/realloc/free 实现您的解决方案并对其进行分析。如果内存分配有问题,您可以使用更好的 malloc 实现,例如 facebook 的jemalloc或 google 的tcmalloc

有关两者的比较,请参阅C++ 内存分配机制性能比较(tcmalloc 与 jemalloc)

它们都非常擅长处理内部/外部碎片。

于 2012-05-21T23:41:18.520 回答