覆盖与分配/解除分配 - 效率

时间:2009-06-02 13:39:45

标签: java .net c++ memory-management

我正在编写一个C ++应用程序,它需要一块内存(大约1000个字节)作为一些文本处理的临时缓冲区。该操作可以每秒重复10,000次。

任何人都可以确认每次需要缓冲区时分配内存会更加昂贵(即带有智能指针的新内存,超出范围时内存被释放),而不是使用固定缓冲区并清除它(写入)每次处理完成后,它的每个字节都为零?

这听起来像C ++的常识,但我在互联网上找不到任何确认它的东西。

具有自动垃圾收集功能的计算机语言(例如Java,.net)的情况是否不同?

8 个答案:

答案 0 :(得分:16)

每次需要时分配和释放内存可能更昂贵,但更大的问题是:它是否重要?写它是最简单的方式,你知道它如何正常工作,不泄漏/破坏内存。只有这样,如果您的表现不够好,请分析代码,看看您可以在哪些方面进行改进。

答案 1 :(得分:6)

虽然我不能给你一个学术上的“确认”,但请考虑一下:

每当CPU执行指令时,都会花费时间。如果您拆除缓冲区,然后重新分配它,CPU将必须执行deallocate / reallocate指令。如果重用缓冲区,则不必执行这些操作。

可以说,重用速度更快(我们甚至没有谈到内存局部性,相同的内存可以留在CPU缓存中)。

话虽如此,除非你正在写一些必须真正,非常紧张的东西(比如实时应用程序),或者除非你已经确定这个缓冲区在你的应用程序中作为瓶颈工作(当你进行性能测量时) ,我会说以最有意义的方式编写它,并且最容易维护。在现代机器上,维护成本可能占软件总成本的比例大于管理1,000字节的性能成本。

答案 2 :(得分:4)

分配内存(通过new或malloc)不会清除它。如果在使用之前必须将内存设置为0,那么您需要将其清除。在这种情况下,使用静态缓冲区是一个巨大的胜利。此外,如果您只使用缓冲区的一部分,则可以跟踪使用的数量,只需清除已使用的部分。

calloc确实将整个缓冲区设置为0,但我无法想象它明显比malloc + memset快。

答案 3 :(得分:2)

关于Java:

一个很大的区别是Java保证新分配的内存为0,并且可能比手动执行此操作更快。此外,Java的垃圾收集器在分配和释放短期对象时非常有效,而另一方面,不必要的长寿命对象可能会导致额外的工作。因此,每次重新定位数组都有可能在Java中比在C ++中表现更好。

但垃圾收集性能很难预测,所以我只是两种方式都做,看看哪个更快。这可能比在这里提出问题并阅读所有答案花费的时间更少。

答案 4 :(得分:1)

与往常一样,回答这个问题的最佳方法是以两种方式实施,然后对两个解决方案进行时间/基准测试以进行实际比较,而不是根据他们的经验对他人的推测或其他方面的工作做出判断(以你未意识到的方式可能与你的不同。

答案 5 :(得分:1)

我将跳过标准“不要担心优化”,因为其他人都已经涵盖了这一点。将缓冲区声明为函数的本地缓冲区最快,并使用memset将其设置为0。使用本地缓冲区,编译器只需将堆栈指针移动到正确的字节数即可“分配”空间。分配不会比这更快。使用visual studio,您可以添加#pragma intrinsic( memset)。我知道gcc也支持内在函数,但我不记得如何告诉它使用它们。我认为最新版本将尽可能使用它们而不被告知。内部memset扩展为一些内联指令,告诉处理器0一系列内存。你不会比这更快。也就是说,如果你不需要,不要将内存归零。

此外,只需使用本地声明的缓冲区,您的代码就会更加清晰。根据您的说法,您的缓冲区不需要在将要使用它的例程范围之外持久化。就现代而言,1000字节很小。使用动态而不是自动内存将添加一堆必须进行测试和维护的代码。不要这样做。自动记忆是显而易见的选择。

答案 6 :(得分:1)

如果您已经对算法效率(大写法等)进行了任何类型的研究,您就会知道(或能够解决)大多数免费商店实施不能保证在较低的(甚至更高的) )将执行的算法迭代的边界,以在免费商店中查找可用块以满足新的/ malloc()请求。

重复使用一个固定缓冲区将提供更高性能的数量级: - 尤其是垃圾收集环境,其中未使用的内存块可以在freestore中停留,直到运行垃圾收集周期。

答案 7 :(得分:0)

我不得不说,当涉及到大内存分配时,最好先做一次而不是每次需要分配一些东西。原因是内存可能变得碎片化并且速度很慢(在内存中创建和删除大量内容需要花费大量资源)。如果您的数据结构为您的操作保留了足够的内存,则可能会更好。这样做的缩小范围是你的大部分记忆都将被占用。

以下是C ++中一个新的和删除的内容:

#include <cstdlib>
using std::malloc;
using std::free;
#include <new>
using std::bad_alloc;

void * operator new(size_t n)
{
    void * p = malloc(n);
    if(!p) throw bad_alloc();
    return p;
}

void operator delete (void *p)
{
    if (p) free(p);
}

做一个新的和删除所有的时间可能是昂贵的!这就是为什么C#和Java等语言比C ++慢的原因。垃圾收集器的唯一优点是它可以为您的程序将内存中的所有内容组合在一起(它会对内存进行defrags)。如果您的程序内存很多东西,这可能会很昂贵。

另外,看看STL中的算法。它可以通过优化某些操作来帮助您。