爬虫遇到栈溢出(stack overflow)的问题

来源:互联网 发布:php详解socket select 编辑:程序博客网 时间:2024/05/17 15:04

今天在用python爬虫抓取网页信息的时候,出现了一个关于栈溢出的错误:

Fatal Python error: Cannot recover from stack overflow.

没有找到正确的解决方案,然后就搜索了跟栈溢出相关的知识并检查了代码,发现了问题所在:使用函数时递归调用次数过多(1000多),导致栈溢出

在Python中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,相当于一次push压栈操作,每当函数返回,相当于一次pop出栈操作。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出。

解决方案:
1.把递归调用函数改用while或者for循环来实现。
2.通过尾递归优化。尾递归是指在函数返回调用自身本身,并且return语句不能包含表达式(既return 函数名(参数))。这种情况下,编译器或者解释器,使递归本身无论调用多少次,都只占用一个栈帧,不会出现栈溢出的情况。

下面分享一下关于栈溢出的个人理解:

在Windows程序的堆栈内存机制里,全局变量(局部的静态变量)存储在堆内存里,堆内存一般较大,不会发生溢出;而函数地址、函数参数、局部变量等信息则存储在栈内存里,栈内存就像我们常说的缓冲区,栈内存一般较小,容易发生溢出。但是效率高。

由于缓冲区溢出而使得有用的存储单元被改写,容易导致程序崩溃或者利用栈溢出进行攻击。

出现栈内存溢出的常见原因有2个:
1. 函数递归调用层次过深,每调用一次,函数的参数、局部变量等信息就压一次栈,并且没有及时出栈。
2. 局部静态变量体积太大

今天爬虫遇到的问题就属于第一种情况,可以通过尾递归优化或者改为非递归来解决。
第二种情况也比较常见,比如在函数里定义很大的局部变量(例如大数组),这种情况可以将局部变量改为静态变量(实质上也是全局变量)。

解决栈溢出的方案总体的思路也是有两个:
1.改用堆内存。这种思路比较常用,以上解决方案也是根据这种思路来做的。
2.增大栈的大小值。

原创粉丝点击