对于那些使用堆栈的实现,堆栈的大小增加是:
- 不适合可用寄存器的变量大小
- 在预先声明的函数中声明的变量的大小在函数的整个生命周期内都存在
- 沿途或语句块中声明的其他局部变量的大小
- 此函数调用的函数使用的最大堆栈大小
- 以上所有内容*递归调用的次数
- 返回地址的大小
退货地址
大多数实现在任何其他数据之前将返回地址压入堆栈。所以这个地址占用空间。
可用寄存器
有些处理器有很多寄存器;但是,可能只有少数可用于传递变量。例如,如果约定允许 2 个变量但有 5 个参数,则 3 个参数将放在堆栈上。
大对象传值时,会占用栈空间。
函数局部变量
这很难计算,因为变量可能会被压入堆栈,然后在不使用时弹出。
某些变量在声明之前可能不会被压入堆栈。因此,如果一个函数在中途返回,它可能不会使用剩余的变量,因此这些变量的堆栈大小不会增加。
编译器可以选择使用寄存器来保存值或将常量直接放入可执行代码中。在这种情况下,它们不会向堆栈添加任何长度。
调用其他函数
该函数可能会调用其他函数。每个调用的函数都可能增加堆栈上的数据量。那些被调用的函数可能会调用其他函数,依此类推。
这又取决于执行时的快照。然而,一个可以通过其他调用的函数产生一个近似的最大堆栈增量。
递归
与调用其他函数一样,递归调用可能会增加堆栈的大小。在函数末尾的递归调用可能会比靠近开头的递归调用增加更多的堆栈。
注册值保存
有时,编译器可能需要比分配的寄存器允许的更多空间来存储数据。因此编译器可以将变量压入堆栈。
为方便起见,编译器可能会将寄存器压入堆栈,例如交换寄存器或更改值的顺序。
总结
函数所需的堆栈空间的确切大小很难计算,并且可能取决于执行的位置。在堆栈大小计算中需要考虑许多项目,例如参数数量和大小以及调用的任何其他函数。由于可变性,大多数堆栈大小测量基于最大大小,或最坏情况大小。堆栈分配通常基于最坏的情况。
对于面试问题,我会提到以上所有内容,这通常会让面试官想要快速进入下一个问题。