我明白了在递归中,每个递归调用是如何堆栈在堆栈上的;如果超过堆栈限制,则会出现堆栈溢出。那么为什么Python的sys.getRecursionLimit()
返回一个数字;递归调用的最大深度?
这不是取决于我在递归函数中做了什么吗?还是以某种方式将变量保存在堆栈以外的其他地方?它是如何工作的?
考虑这个问题的一个简单方法是,Python堆栈实际上并不是一个连接所有帧的巨大数组,而是一个帧的链表。1但如果你用C语言来思考,即使这样也会产生误导。你好像是:
还是以某种方式将变量保存在堆栈以外的其他地方?
确实如此--在CPython中,局部变量2存储在堆分配的frame对象上的数组中--但这通常不是相关的问题。
之所以存在recursionerror
限制,是因为大多数深度为1000的Python代码在memoryerror
或堆栈溢出segfault失败之前可能需要很长时间分配一整串Python帧,因此最好在分配所有内存和烧录所有CPU之前停止。
更重要的是,正如tdelaney在一篇评论中指出的那样,在Python中从这两种情况中的任何一种恢复都是非常困难的--但是从recursionerr
恢复非常简单;它为您将堆栈展开到递归的顶部,并使您处于可预测的状态。
但这一经验法则并不适用于每一个程序,只适用于大多数程序--所以如果你知道你有一个算法可以在没有任何问题的情况下达到几千帧深度,Python允许你将极限提高到,比方说10000而不是1000。
1。这是过于简化的,因为(至少在CPython中)解释器实际上经常链接C堆栈上的调用--但记住在Python中每次递归时堆分配一个新的frame对象(以及frame分配的其他东西)仍然是有用的,无论解释器是否递归。(特别是因为Python被定义为从不在Python级别执行尾部调用消除,即使解释器实际上在eval循环中这样做。)
2。从技术上讲,在Python中,所有变量都存储在一个名称空间中,这是一个从名称到对值的引用的映射。但CPython通过存储指针数组,然后让编译器将局部引用转换为数组查找而不是映射查找来优化局部变量。
3。当然,“某处”是未指定的--Python是垃圾收集的,无论是像CPython那样使用自动refcounting加循环检测器,还是像Jython那样使用任何底层JVM。但在CPython中,还有一个定义的C API,其中对象是指向结构的C指针--您可以通过id
函数看到这个指针的值。
4。此外,864字节主要是指向单个不可变0
对象的100个指针的列表,而不像C语言,后者有100个单独的可变int
槽,其中都包含值0
。
让我们回到函数,进行更深入的研究。 我们的第一个主题是 递归(recursion)。 如果你不是刚接触编程,那么你可能已经很熟悉它了,那么你可以跳过这一章。 递归是一种编程模式,在一个任务可以自然地拆分成多个相同类型但更简单的任务的情况下非常有用。或者,在一个任务可以简化为一个简单的行为加上该任务的一个更简单的变体的时候可以使用。或者,就像我们很快会看到的那样,处理某些数据结构。 当一个函数解决一
问题内容: 我在IE浏览器中遇到了一些客户端Javascript堆栈溢出问题,这是在第三方库中发生的,该库进行了一些函数调用,并且由于某些原因,它们有时仅由于IE栈限制低而在IE中制动。 然后,我编写了一个小的测试HTML,以测试某些浏览器的堆栈大小限制,并发现与运行Windows 7 OS,8Gb RAM的笔记本电脑上运行的FF 7或Chrome 14相比,IE8实际上具有较小的堆栈限制: 当值
我正在研究一般图的非递归DFS和BFS。除了前者使用堆栈而不是队列之外,唯一的区别在于它“延迟检查顶点是否已被发现,直到顶点从堆栈中弹出,而不是在推送顶点之前进行此检查”。为什么此“访问”检查顺序不同?或者换句话说,我们可以通过简单地用堆栈替换BFS中的队列来将BFS更改为非递归DFS吗? 我检查了所有我能找到的帖子,比如这个和这个,但是没有一个能澄清这个问题。
代码运行良好。只是我不明白。在递归部分有困难的。在此部分中:我的想法是,首先它将一直执行直到一个阈值。则它将执行一次。因此只会被赋值一次。显然那不是真的。 对我来说,困难的部分是在方法中,做什么?在方法中,、做什么?
我在处理中运行递归方法,但当作业太大时,它会给我以下错误: 由于等待数据包139时超时,事件线程崩溃。 但当递归很小时,它可以工作。有没有办法增加堆栈以解决更大的递归问题? 这是我的代码,用于在屏幕上绘制人物。它适用于较小的数字,但不适用于较大的数字。 回溯:
问题内容: 进程的大小是否有限制?它是否仅取决于机器的性能?我想知道这一点,以限制对函数的递归调用的深度。 谢谢。 问题答案: 堆栈通常受资源限制的限制。您可以使用以下命令查看安装的默认设置: (这表明我的是8MB,这是巨大的)。 如果删除或增加该限制,您仍将无法使用计算机中的所有RAM作为堆栈- 堆栈从进程地址空间顶部附近的一点向下增长,并在某个时刻它将运行到您的代码,堆或已加载的库中。