分配多个小内存还是少分配几个大内存更快?

7
使用malloc分配内存时,是多次分配较小的数据块还是少次分配较大的数据块通常更快?例如,假设您正在处理一个具有黑色像素和白色像素的图像文件。您正在遍历像素,并希望将每个黑色像素的x和y位置保存在一个新结构中,该结构还具有指向前一个和后一个像素的x和y值的指针。是通过遍历像素为每个黑色像素的x和y值及其指针分配一个新结构,还是先通过遍历获得黑色像素的数量,然后使用仅包含x和y值但没有指针的结构分配大块内存,再次遍历并将x和y值保存到该数组中更快?我假设某些平台可能比其他平台更快,但是大家认为哪种方法通常更快?
14个回答

21

这要看情况:

  • 多次小的分配意味着需要多次操作,速度会变慢
  • 对于小的内存分配可能有特殊/快速的实现方式。

如果我很在意性能,我会进行测试!如果我非常在意,并且无法猜测,那么我可能会同时实现两种方式,在目标机器上运行时进行测试,并相应地进行调整。

一般来说,我会认为越少越好:但是有些大小和运行时库的实现方式会将(足够)大的内存分配委托给(相对较慢的)操作系统,而(足够)小的内存分配则会从(已经分配好的相对较快的)堆中提供。


而你如何一般性地知道你的系统是否有这样一个神奇的库呢? - Juergen
3
引用ChrisW的话:“如果我在意的话,我会测量它!” - danielschemmel
1
@all+author:我只是好奇,为什么有人在这里提出问题,然后接受一个回答,而那个回答者自己却说他并不关心(dionadar引用了他的话)。我知道,我们在这里不是在从事科学研究,但在这种情况下为什么还要提问呢? - Juergen
1
@Juergen 我可能表达得不太好,但我的意思是,如果他在意的话,他应该自己测试一下。猜测也许有可能(甚至可能很有趣),但实际答案是与平台相关的。 - ChrisW
@Juergen,我没有回答你关于“拥有这样一个奇妙的库”的第一条评论,因为我不理解它。也许没有一般的方法可以知道,也没有一般的方法可以“拥有”它:拥有任何特定的库都是一个具体的情况。话虽如此,如果请求足够大,将委托给操作系统,我认为 MSVC 运行时库(例如)就是这样做的。 - ChrisW
显示剩余5条评论

15

分配大块内存更有效率;此外,由于您使用更大的连续块,因此具有更高的引用局部性,在生成内存结构后遍历它应该也更有效率!此外,分配大块应有助于减少内存碎片。


请注意,如果/当您释放它们时,较大的块可能会导致更严重的碎片化问题。 - Javier
3
一般而言,在内存碎片问题上,释放由多个小块组成的一个大块的效果要优于逐个分配/释放这些小块。我无法在500+字符内证明它的正确性,但你也无法证明自己大胆的陈述。 - Juergen

5

一般来说,少次分配更大的内存块速度会更快。每次调用malloc()都会涉及一些开销。


2
更多信息,请查看Bonwick在Usenix上关于slab分配的论文。http://www.usenix.org/publications/library/proceedings/bos94/full_papers/bonwick.a - Dana the Sane

4

3

分配内存是一项工作。在分配内存块时所需的工作量通常与内存块的大小无关。你可以从这里开始计算。


@ovanes:就我所理解的,你说的是Neil的反面。而且你并不试图打败编译器,而是一个库例程。所以你的观点在这里是错误的。当你的分配问题如此复杂,以至于你无法击败这个例程(从问题中我没有看到这一点),那么你就有麻烦了,是的!或者你应该学习一些书。 - Juergen

3

在性能敏感的代码中最好不要分配内存。预先分配你需要的内存,然后尽可能多地使用和重复使用。

通常来说,内存分配是一个相对较慢的操作,所以不要比必要的更频繁地进行它。


2
这个问题是实用主义的,也就是说,答案取决于具体情况。
如果你有很多像素,其中只有少数是黑色的,那么计算它们可能是最高代价的。
如果你正在使用C++,正如你的标签所示,我强烈建议使用STL,例如std::vector。
如果我没记错的话,vector的实现采用了实用主义的方法进行分配。有一些分配策略的启发式方法,其中一个信息丰富的方法是:
class SampleVector {
    int N,used,*data;
public:
    SampleVector() {N=1;used=0;data=malloc(N);}

    void push_back(int i)
    {
        if (used>=N)
        {
            // handle reallocation
            N*=2;
            data=realloc(data,N);
        }
        data[used++]=i;
    }
};

在这种情况下,每次重新分配内存时,您会将分配的内存量加倍。这意味着重新分配的频率逐渐减半。
如果您可以使用STL实现,则应该使用它,因为它已经进行了良好的调整!

我不同意。无论如何,您都要遍历像素 - 不要尝试保存要存储的像素的额外迭代。幕后std :: vector的重新分配和复制需要更多时间。 - libeako
当然,这仍然取决于您存储的像素数量与您必须迭代的数量之间的函数关系。 - Dave Gamble

2

通常情况下,malloc操作是比较昂贵的。它需要从内存中找到一个合适的块来分配内存,并跟踪非连续的内存块。在一些库中,你会发现有小型内存分配器,它们试图通过分配一个大块并管理分配器中的内存来最小化影响。

Alexandrescu在《现代C++设计》中解决了这个问题,在Loki库中也有类似的库可供参考。


2
另一个需要考虑的问题是它如何与线程交互。在多线程应用程序中频繁使用 malloc 会严重拖慢性能。在这种环境下,最好使用可扩展的分配器,比如英特尔的 Thread Building Blocks 或者 Hoard 中使用的分配器。malloc 的主要限制是存在单个全局锁,所有线程都要争夺它。情况可能非常糟糕,甚至加入一个新线程也会显著地减慢应用程序的速度。

1

如前所述,malloc 是代价高昂的,因此分配较少可能会更快。 此外,在大多数平台上处理像素将具有更少的缓存未命中并且速度更快。 但是,并非每个平台都能保证这一点


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接