代码之家  ›  专栏  ›  技术社区  ›  Steven Smethurst

大缓冲区和大静态缓冲区,有什么优势吗?

  •  3
  • Steven Smethurst  · 技术社区  · 16 年前

    考虑下面的代码。

    在1000次连续执行中,dosomething1()比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 回复  |  直到 16 年前
        1
  •  8
  •   Brian R. Bondy    16 年前

    静态缓冲器的缺点:

    • 如果您需要线程安全,那么使用静态缓冲区可能不是一个好主意。
    • 在程序结束之前,内存不会被释放,因此会使内存消耗更高。

    静态缓冲器的优点:

    • 静态缓冲区的分配较少。您不需要每次在堆栈上分配。
    • 对于静态缓冲区,由于分配太高,堆栈溢出的可能性较小。
        2
  •  6
  •   Drew Hoskins    16 年前

    如果在vc++编译器中启用了/gs,则堆栈分配会稍微昂贵一些,因为它可以对缓冲区溢出进行安全检查(默认情况下启用了/gs)。实际上,您应该分析这两个选项,看看哪个更快。静态内存中的缓存位置与堆栈中的缓存位置可能会产生差异。

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

    _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
    
        3
  •  4
  •   Adam Rosenfield    16 年前

    两者之间几乎没有任何速度差。在堆栈上分配缓冲区的速度非常快——它只是将堆栈指针递减一个值。但是,如果您在堆栈上分配一个非常大的缓冲区,则有可能溢出堆栈并导致segfault/访问冲突。相反,如果您有大量的静态缓冲区,那么您将大大增加程序的工作集大小,尽管如果您有良好的引用位置,这将有所减轻。

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

        4
  •  2
  •   Accipitridae    16 年前

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

    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);
           ...
        }
    }
    

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

        5
  •  2
  •   anon    16 年前

    我是这里唯一一个使用多线程软件的人吗?在这种情况下,静态缓冲区是绝对不允许的,除非您希望将自己投入到大量的性能循环锁定和解锁中。

        6
  •  0
  •   redcalx    16 年前

    正如其他人所说,堆栈分配速度非常快,对于更复杂的对象(如arraylist或hashtable(现在列表<>和字典<,>,在通用世界中)来说,不必每次重新分配的速度可能更快,因为在这些对象中,每次都有要运行的构造代码,而且如果容量设置不正确,那么yo每次容器达到容量时都会有不需要的重新分配,必须分配新内存,并将内容从旧内存复制到新内存。我经常会使用工作列表中允许增长到所需大小的对象,并通过调用clear()重新使用它们,这会使分配的内存/容量保持不变。但是,如果您有一个碰巧分配了大量不经常发生或只发生一次的内存的胭脂调用,那么应该小心内存泄漏。