是什么导致Python分段错误?


82

我正在用Python实现Kosaraju的强连接组件(SCC)图搜索算法。

该程序可以在较小的数据集上很好地运行,但是当我在超大图形(超过800,000个节点)上运行它时,它会显示“ Segmentation Fault”。

可能是什么原因造成的?谢谢!


附加信息:首先,我在超大型数据集上运行时遇到此错误:

"RuntimeError: maximum recursion depth exceeded in cmp"

然后我使用设置重置递归限制

sys.setrecursionlimit(50000)

但是出现了“细分错误”

相信我这不是一个无限循环,它可以在相对较小的数据上正确运行。程序是否可能耗尽了资源?


10
也许您可以看看CrashingPython
Abhijit

2
这是在纯Python中运行还是在使用C扩展模块?如果它是纯Python,那是一个bug,恭喜。如果您使用的是交流模块,则段故障可能来自那里。
aaronasterling'4

这是纯Python。该程序在相对较小的数据集上运行良好,这使我认为代码是正确的。
xiaolong 2012年

根据Python文档:
James Thiele

2
根据Python文档::::::最高可能的限制取决于平台。当用户拥有需要深度递归的程序和支持更高限制的平台时,用户可能需要将限制设置为更高。这应该谨慎进行,因为限制太高会导致崩溃。:::::::您未指定操作系统。对崩溃的引用可能意味着您的操作系统上存在段故障。尝试较小的堆栈。但是IIRC您正在使用的算法会将rntire SSC放在堆栈中,因此您可能用完堆栈。
詹姆斯·锡勒

Answers:


80

当python扩展(用C编写)试图访问无法访问的内存时,会发生这种情况。

您可以通过以下方式对其进行跟踪。

  • sys.settrace在代码的第一行添加。
  • gdb按照Mark此答案中所述使用。.在命令提示符下

    gdb python
    (gdb) run /path/to/script.py
    ## wait for segfault ##
    (gdb) backtrace
    ## stack trace of the c code
    

2
谢谢,但是我的代码是纯python,会有所作为吗?
xiaolong 2012年

检查您正在使用哪些python模块?有些模块是用python编写的,其他模块是用C编写的。我认为您需要报告一个错误。
Shiplu Mokaddim'4

1
相似,也很有帮助:stdlib的跟踪模块仅帮助我解决了登台服务器上的分段错误,无需安装新的依赖项,也无需修改代码。
2015年

3
在OSX Sierra上,gdb被lldb取代
kthouz '16


51

我了解您已经解决了您的问题,但是对于其他阅读此线程的人来说,这就是答案:您必须增加操作系统为python进程分配的堆栈。

这样做的方式取决于操作系统。在linux中,您可以使用以下命令检查ulimit -s当前值,并可以使用以下命令增加当前值:ulimit -s <new_value>

尝试将前一个值加倍,如果不起作用则继续加倍,直到找到一个可用或用完的值。


检查是否要达到ulimit max的一种好方法是运行lsof和使用grepwc -l跟踪所有内容。
13年

我同意。通过修复Python和C ++实现上的段错误,这实际上对Kosaraju的SCC实现有效。<br/>对于我的MAC,我通过以下方式找到了可能的最大值:
Rock

4
请注意,ulimit值仅针对在其中执行的特定shell进行修改,这样您就不会意外修改整个系统的值
Tanmay Garg,2016年

1
我这样做了,最终以ulimit -s 16384结尾,但是运行后仍然出现分段错误。
Sreehari R

@SreehariR尝试进一步增加它。但是,这也可能是python扩展的问题(如果您使用的是扩展名),(其他答案)[ stackoverflow.com/a/10035594/25891]建议如何调试
Davide

18

细分错误是一种常见错误,其原因可能有很多:

  • 记忆不足
  • 内存错误
  • 使用查询从数据库中获取巨大的数据集(如果获取的数据大小大于swap mem)
  • 错误的查询/错误代码
  • 具有长循环(多次递归)

2

通过在Python(Python segfault ..谁知道!)和C ++实现上修复segfault,更新了ulimit对我的Kosaraju的SCC实现有效。

对于我的MAC,我通过以下方式找到了可能的最大值:

$ ulimit -s -H
65532

如何更新该值?该值是什么类型的单位?
巴勃罗

2

Google搜索找到了这篇文章,但没有看到下面的“个人解决方案”讨论。


我最近在Linux的Windows子系统上对Python 3.7的烦恼是:在具有相同Pandas库的两台计算机上,一台给我segmentation fault,另一台报告警告。不清楚哪个是较新的,而是“重新安装”pandas可以解决问题。

我在越野车上运行的命令。

conda install pandas

更多详细信息:我正在运行相同的脚本(通过Git同步),并且两者都是带有WSL + Anaconda的Windows 10计算机。这里有截图以说明问题。同样,在命令行python会抱怨的机器上Segmentation fault (core dumped),Jupyter实验室每次仅重新启动内核一次。更糟糕的是,根本没有发出警告。

在此处输入图片说明


几个月后更新:我不再在Windows计算机上托管Jupyter服务器。现在,我在Windows上使用WSL来获取在Linux服务器上打开的远程端口,并在远程Linux机器上运行所有作业。我已经好几个月没有遇到任何执行错误了:)


0

在RPI上升级dlib后,我遇到了这种分段错误。我按照上面Shiplu Mokaddim的建议回溯了堆栈,并将其放置在OpenBLAS库中。

由于OpenBLAS也是多线程的,因此在多线程应用程序中使用它会成倍地增加线程数量,直到出现分段错误。对于多线程应用程序,将OpenBlas设置为单线程模式。

在python虚拟环境中,通过编辑来告诉OpenBLAS仅使用单个线程:

    $ workon <myenv>
    $ nano .virtualenv/<myenv>/bin/postactivate

并添加:

    export OPENBLAS_NUM_THREADS=1 
    export OPENBLAS_MAIN_FREE=1

重新启动后,我能够在rpi3b上运行我所有的图像识别应用程序,这些应用程序以前曾崩溃过。

参考:https : //github.com/ageitgey/face_recognition/issues/294


-1

看起来您的堆栈内存不足。您可能希望像Davide所说的那样增加它。要在python代码中执行此操作,您需要使用线程运行“ main()”:

def main():
    pass # write your code here

sys.setrecursionlimit(2097152)    # adjust numbers
threading.stack_size(134217728)   # for your needs

main_thread = threading.Thread(target=main)
main_thread.start()
main_thread.join()

资料来源:c1729的codeforce帖子。用PyPy运行它有点棘手

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.