一、c/c++的堆栈在那些地方使用
??????? 堆栈(即栈)的使用,通常用来存储局部变量和函数参数,函数调用后返回的地址。
??????? 注:注意堆栈和堆的概念,堆的使用,即动态内存分配。程序在运行的时候用malloc或new申请任意大小的内存,程序员自己负责在适当的时候用free或 delete释放内存。
????????C 和 C++ 都大量使用堆栈。 通常,堆栈使用很明确的包含: ??? 【1】函数的返回地址。 ??? 【2】必须保留的寄存器。 ??? 【3】局部变量,包括局部数组、结构、联合,以及 C++ 中的类。 但有些堆栈的使用并不明显,如: ??? 【1】如果局部整数或浮点变量被溢出(即未分配给寄存器),则为它们分配堆栈内存。 ??? 【2】结构通常分配给堆栈。 一个空间相当于 sizeof(struct)填充到多个字节被保留在堆栈上, 但是,编译器可能会尝试将结构分配给寄存器。 ??? 【3】如果在编译时知道数组的大小,则编译器会在堆栈上分配内存。 同样,一个空间相当于 sizeof(array)填充到多个字节被保留在堆栈上。
??? 【4】一些优化可以引入新的临时变量来保存中间结果。 优化包括:公共表达消除、生存范围拆分和结构拆分。 编译器尝试将这些临时变量分配给寄存器。 如果没有,它会将它们溢出到堆栈中。 ??? 【5】通常,低位处理器编译(16bit/T32)的代码比高位处理器编译(32bit/T32)的代码更多地使用堆栈。 因为高位处理编译器比低位的具有更多个寄存器。 ?? 【6】某些编译器要求某些函数参数传递通过堆栈或寄存器,具体取决于它们的类型、大小和顺序。
二、c/c++的堆栈该如何使用
??????? 【1】操作系统负责分配应用程序的堆栈和堆。编译器也有责任,但主要依靠操作系统来完成。堆栈是有限的,而堆不是。因此,在堆上分配非固定大小的对象(通常是编译时大小未知的数组)是不错的选择,建议任何超过几个KB的内容通常最好放在堆中。
??????? 【2】能使用堆栈的优先使用堆栈,而非堆,基于堆栈的对象更容易跟踪何时抛出异常。当然,您可以使用一个智能指针,它可以是一个基于堆栈的包装器,用于一个基于堆的对象的原始指针。
??????? 【3】尽量编写只需要少量变量的小函数。
??????? 【4】尽量避免使用大型局部结构或数组。
??????? 【5】尽量通过使用替代算法来避免递归,尤其是递归函数还定义变量的情况。
??????? 【6】函数中每个点在任何给定时间使用的变量数量最小化。
三、c/c++的堆栈使用追踪优化
??????? 建议在调试时,手动追踪堆栈使用情况并作出优化: ??? ??????? 【1】利用编译器生成静态调用图,显示所有函数的信息,包括堆栈使用。 ??? ??????? 【2】使用 .debug_frame来显示的 DWARF 信息进行追查。 ??? ??????? 【3】使用--info=stack等编译指令列出所有全局符号的堆栈使用情况。 ??? ??????? 【4】使用调试器在堆栈中的最后一个可用位置设置观察点,并查看观察点是否被命中。 ??????????? 【5】应用程序完成执行后,检查内存的堆栈空间以查看有多少已知值已被覆盖,有多少一使用部分有垃圾。 ??????? ??? 【6】计算垃圾值的数量并乘以 sizeof(value), 给出它们的大小,以字节为单位。追踪其堆栈的大小是如何增长的,以字节为单位。 ??? ??????? 【7】采用异常捕获设计,堆栈溢出到禁止区域,则会发生数据中止,就可能会被调试器捕获。
|