虽然其他答案谈谈如何要么避免递归完全,或如何使用尾递归,或如何简单地设置一个较大的堆栈大小,我认为完整性,这是值得考虑的内存使用模式(以回答“如何让更多的内存...在很多递归上”)。
出于习惯,许多程序员将分配缓冲区递归函数里面,并重新分配新的缓冲区,当函数被递归调用:
int recursive_function(int x)
{
if (1 == x)
return 1;
int scratchpad[100];
... // use scratchpad
return recursive_function(x-1) + scratchpad[x-1];
}
由于这是一个一次性的样品,我不会打扰担心关于无效输入(负值,大于100的值),我会假设有人提出关于编程的问题要么知道如何做,要么足够聪明以找出答案。
重要这里的一点是,scratchpad堆栈每一次recursive_function()被称为的占用400个字节(32位机器上,800个字节的64位计算机上),所以如果recursive_function()被递归调用100倍,然后40000字节(或80000个字节的64位计算机上)的堆栈空间被用于缓存,它很可能,你可以修改函数重用每次调用同一个缓冲区:
int recursive_function(int x, int* buffer, int buffer_length)
{
if (1 == x)
return 1;
... // use buffer (and buffer_length to avoid overflow)
int temp_value = buffer[x-1];
return recursive_function(x-1, buffer, buffer_length) + temp_value;
}
当然你可以改为使用std::vector,它为你处理一些细节,以防止内存泄漏和缓冲区溢出(并且,对于记录,将数据保存在堆上[见脚注],这意味着它可能会使用较少的堆栈空间)。
40k甚至80k可能看起来不多,但事情可以加起来。如果该函数没有其他堆栈分配变量,那么这可以支配堆栈空间(也就是说,如果它不是用于缓冲区占用的额外空间,则可能可以调用该函数的次数)。
这看起来很明显,即使在非递归函数中也是如此,即but it does come up。另外,缓冲区并不总是与数组一样明显。例如,它们可能是字符串或对象。
脚注:STL容器,比如数组不一定提上堆的所有数据。他们实际上采用模板参数来指定使用的内存分配;它只是默认使用的分配器将数据放在堆上。很明显,除非你指定一个以某种方式将数据放入堆栈的分配器,否则最终结果将是相同的:使用STL容器可能比使用堆栈分配的数组或对象使用更少的内存。
我说“可能”,因为虽然数据保存在堆(或其他地方),但容器只能通过它在内部保存的指针访问该数据,如果容器在堆栈上,那么这些指针将驻留在堆栈和这些指针占用空间。因此,一个或两个元素std::vector实际上可能占用堆栈上的空间多于对应的数组。