什么是C ++的递归调用的最大数量的量级?(What is the order of magnitu

2019-09-16 13:23发布

我有一个递归函数调用自己的一个非常大的数量给予一定的投入时间 - 这正是它应该做的。 我知道我的功能是不是无限循环 - 它只是达到某个号码的呼叫和溢出。 我想知道这是否是把太多的内存堆栈,或者呼叫数只是一个正常的限制上的问题。 显然,这是很难说的呼叫这是最大的一个具体的数字,但有谁能够给我量级的粗略估计? 它是在几千? 数百? 百万?

Answer 1:

这完全取决于你多少信息使用堆栈。 然而,在Windows默认的堆栈是1MB和Unix上的默认堆栈为8MB。 只需拨打电话可涉及推几32位寄存器和一个返回地址,比方说,所以你可以在看,也许20字节的电话​​,这将使最大在Windows上约50K和400K基于UNIX的一个空函数。

当然,据我所知,您可以更改堆栈大小。



Answer 2:

因此,当你已经猜到了,问题是(齐名)栈溢出。 每个呼叫,需要建立一个新的堆栈帧,推新的信息送到堆栈上; 堆栈大小是固定的,并最终耗尽。

什么设置堆栈大小? 这是编译器的性质 - 也就是说,它是固定的二进制可执行文件。 在微软的编译器(在VS2010中使用),它默认为1兆字节,你可以在编译器选项“/ F”覆盖它(见这里的一个'03例子,但语法是一样的)。

这是很难弄清楚有多少调用,相当于在实践中。 被确定的函数的堆栈大小由它的局部变量,返回地址的大小,以及参数的传递(有些人可能会进入堆叠),而且大部分依赖于建筑,也。 一般来说,你可以假设的是,后两个是不到一百个字节(这是一个总的估计)。 前者取决于你的函数做什么。 如果假设函数需要,说,256个字节的堆栈上,然后用1M的堆栈,你会得到4096的功能溢出之前调用 - 但是这并没有考虑到的主要功能等的开销

你可以尽量减少局部变量和参数的开销,但真正的解决办法是尾调用优化的 ,在编译器释放调用函数,它调用递归函数。 你可以阅读更多关于做,在MSVC 这里 。 如果你不能做到尾调用,你不能接受的减少你的堆栈大小,那么你可以看看与“/ F”参数,或(首选的解决方案),看一个重新设计,增加堆栈大小。



Answer 3:

你的一个选择可能会改变/增加缺省堆栈大小。 这里有一种方法http://msdn.microsoft.com/en-us/library/tdkhxaks(v=vs.80).aspx



Answer 4:

有测量堆栈使用的工具。 他们填写堆栈事先有一定字节模式,并期待以后到什么解决这一问题得到了改变。 有了这些,你可以找出你如何接近极限得到。

也许的Valgrind的工具之一,能做到这一点。



Answer 5:

堆栈空间通过一个递归函数所使用的量取决于递归的深度和存储器空间由每个呼叫所使用的量。

递归的深度是指在任何特定时刻的呼叫活跃的级别数。 例如,二叉树可能有,比如说,一万个节点,但如果它很好的平衡,你可以没有更多的20个并发活动呼叫穿越它。 如果不是很好的平衡,最大深度可能会大得多。

内存每次调用使用量取决于您的递归函数声明的变量的总规模。

有递归的最大深度没有固定的限制; 如果你的总使用量超过系统规定的堆栈限制,你会得到一个堆栈溢出。

您可能能够通过某种方式减少您的递归的深度可能通过重组不管它是你正在穿越减少内存使用,(你并没有告诉我们很多有关),或通过减少声明的局部对象的总大小您的递归函数内(注意,在堆上分配的对象不利于堆栈大小),或两者的某种组合。

正如其他人所说的,你也许可以增加你允许的堆栈大小,但是这很可能将是有限的使用 - 这是你要在运行程序之前做额外的事。 它也可能消耗资源,并与系统(限制强加的一个原因)上的其他进程干扰。

改变算法,以避免递归可能是一种可能性,但同样,我们没有足够的信息来多讲一点。



文章来源: What is the order of magnitude of the maximum number of recursive calls in C++?