大缓冲区与大型静态缓冲区有比较优势吗?

时间:2009-05-08 17:54:03

标签: c++ optimization performance

请考虑以下代码。

DoSomething1()在连续1000次执行中比DoSomething2()更快吗? 我假设如果我在哪里调用DoSomething1()它1000次,那么它会比调用DoSomething2()1000次更快。

将所有大缓冲区设为静态是否有任何不利之处?

#define MAX_BUFFER_LENGTH 1024*5 
void DoSomething1()
{
    static char buf[MAX_BUFFER_LENGTH] ; 
    memset( buf, 0, MAX_BUFFER_LENGTH );
}

void DoSomething2()
{
    char buf[MAX_BUFFER_LENGTH] ; 
    memset( buf, 0, MAX_BUFFER_LENGTH );
}

感谢您的时间。

6 个答案:

答案 0 :(得分:8)

静态缓冲区的缺点:

  • 如果你需要线程安全,那么使用静态缓冲区可能不是一个好主意。
  • 直到程序结束才会释放内存,从而使内存消耗更高。

静态缓冲区的优点:

  • 静态缓冲区的分配较少。您不需要每次都在堆栈上进行分配。
  • 使用静态缓冲区,由于分配过高,堆栈溢出的可能性会降低。

答案 1 :(得分:6)

如果在VC ++编译器中启用了/ GS,则堆栈分配会稍微贵一些,这样可以对缓冲区溢出进行安全检查(默认情况下/ GS处于打开状态)。真的,你应该分析这两个选项,看看哪个更快。静态内存中的缓存局部性与堆栈上的缓存局部性可能会产生差异。

这是非静态版本,VC ++编译器带有/ O2。

_main   PROC                        ; COMDAT
; Line 5
    mov eax, 5124               ; 00001404H
    call    __chkstk
    mov eax, DWORD PTR ___security_cookie
    xor eax, esp
    mov DWORD PTR __$ArrayPad$[esp+5124], eax
; Line 7
    push    5120                    ; 00001400H
    lea eax, DWORD PTR _buf$[esp+5128]
    push    0
    push    eax
    call    _memset
; Line 9
    mov ecx, DWORD PTR __$ArrayPad$[esp+5136]
    movsx   eax, BYTE PTR _buf$[esp+5139]
    add esp, 12                 ; 0000000cH
    xor ecx, esp
    call    @__security_check_cookie@4
    add esp, 5124               ; 00001404H
    ret 0
_main   ENDP
_TEXT   ENDS

这是静态版本

;   COMDAT _main
_TEXT   SEGMENT
_main   PROC                        ; COMDAT
; Line 7
    push    5120                    ; 00001400H
    push    0
    push    OFFSET ?buf@?1??main@@9@4PADA
    call    _memset
; Line 8
    movsx   eax, BYTE PTR ?buf@?1??main@@9@4PADA+3
    add esp, 12                 ; 0000000cH
; Line 9
    ret 0
_main   ENDP
_TEXT   ENDS
END

答案 2 :(得分:4)

两者之间几乎没有任何速度差异。在堆栈上分配缓冲区非常快 - 所有这一切都是将堆栈指针递减一个值。但是,如果在堆栈上分配一个非常大的缓冲区,则可能会溢出堆栈并导致段错误/访问冲突。相反,如果你有很多静态缓冲区,你会大大增加程序的工作集大小,但如果你有很好的引用位置,这会有所减轻。

另一个主要区别是堆栈缓冲区是线程安全的和可重入的,而静态缓冲区既不是线程安全的也不是可重入的。

答案 3 :(得分:2)

您还可以考虑将代码放入类中。例如。

之类的东西
const MAX_BUFFER_LENGTH = 1024*5; 
class DoSomethingEngine {
  private:
    char *buffer;
  public:
    DoSomethingEngine() {
      buffer = new buffer[MAX_BUFFER_LENGTH];
    }
    virtual ~DoSomethingEngine() {
       free(buffer);
    }
    void DoItNow() {
       memset(buffer, 0, MAX_BUFFER_LENGTH);
       ...
    }
}

如果每个胎面只分配自己的发动机,这是安全的。它避免了在堆栈上分配大量内存。堆上的分配是一个很小的开销,但如果您多次重用该类的实例,则这可以忽略不计。

答案 4 :(得分:2)

我是唯一一位从事多线程软件工作的人吗?在这种情况下,静态缓冲区是绝对禁止的,除非你想要承诺锁定和解锁的许多性能。

答案 5 :(得分:0)

正如其他人所说的堆栈分配非常快,对于更复杂的对象,例如ArrayList或HashTable(现在List<>和Dictionary<,>),每次不必重新分配的加速可能更大。通用世界)每次都有运行的构造代码,如果容量设置不正确,那么每次容器达到容量时都会有不必要的重新分配,并且必须分配新内存并将内容从旧内存复制到新内存。我经常有工作List<>我允许增长到任何大小的对象,我通过调用Clear()重用它们 - 这使得分配的内存/容量保持不变。但是,如果你的胭脂调用碰巧分配了大量内存,而这种内存不经常发生或只发生一次,你应该警惕内存泄漏。