Что вызывает ошибку сегментации Python?

85

Я реализую алгоритм поиска графа Strong Connected Component (SCC) Kosaraju в Python.

Программа отлично работает с небольшим набором данных, но когда я запускаю ее на сверхбольшом графе (более 800 000 узлов), появляется сообщение «Ошибка сегментации».

Что может быть причиной этого? Спасибо!


Дополнительная информация: сначала я получил эту ошибку при работе с сверхбольшим набором данных:

"RuntimeError: maximum recursion depth exceeded in cmp"

Затем я сбрасываю предел рекурсии, используя

sys.setrecursionlimit(50000)

но получил "Ошибка сегментации"

Поверьте, это не бесконечный цикл, он работает правильно на относительно небольших данных. Возможно программа исчерпала свои ресурсы?

сяолун
источник
10
Может быть, вы можете посмотреть CrashingPython
Abhijit
2
Это работает на чистом Python или вы используете модуль расширения C? Если это чистый Python, то это ошибка, и мои поздравления. Если вы используете модуль ac, вероятно, оттуда исходит segfault.
aaronasterling
это чистый питон. Программа отлично работает на относительно небольшом наборе данных, и это заставило меня подумать, что код правильный.
xiaolong
Согласно документации Python:
Джеймс Тиле
2
Согласно документации Python :::::: Максимально возможный предел зависит от платформы. Пользователю может потребоваться установить более высокий предел, если у него есть программа, требующая глубокой рекурсии, и платформа, поддерживающая более высокий предел. Это следует делать с осторожностью, поскольку слишком высокий предел может привести к сбою. :::::: Вы не указали ОС. Ссылка на сбой может означать ошибку сегментации в вашей ОС. Попробуйте меньшую стопку. Но алгоритм IIRC, который вы используете, помещает все SSC в стек, так что у вас может закончиться стек.
Джеймс Тиле

Ответы:

80

Это происходит, когда расширение Python (написанное на C) пытается получить доступ к недоступной памяти.

Вы можете отследить это следующими способами.

  • Добавьте sys.settraceв самую первую строку кода.
  • Используйте, gdbкак описано Марком в этом ответе .. В командной строке

    gdb python
    (gdb) run /path/to/script.py
    ## wait for segfault ##
    (gdb) backtrace
    ## stack trace of the c code
    
Шиплу Мокаддим
источник
2
спасибо, но мой код - чистый питон, это имеет значение?
xiaolong
Проверьте, какие модули Python вы используете? Некоторые модули написаны на python, а другие - на C. Думаю, вам нужно сообщить об ошибке.
Шиплу Мокаддим
1
аналогично, также полезно: модуль трассировки stdlib просто помог мне разобраться с ошибкой сегментации на промежуточном сервере без установки новой зависимости и без изменения кода.
дрифтер
4
в OSX Sierra gdb был заменен на lldb
kthouz 01
54

Я понимаю, что вы решили свою проблему, но для других, читающих эту ветку, вот ответ: вам нужно увеличить стек, который ваша операционная система выделяет для процесса python.

Способ сделать это зависит от операционной системы. В Linux вы можете проверить с помощью команды ulimit -sсвое текущее значение и увеличить его с помощьюulimit -s <new_value>

Попробуйте удвоить предыдущее значение и продолжайте удваивать, если оно не работает, пока не найдете то, которое работает или не исчерпает память.

Давиде
источник
Также хороший способ проверить, сталкиваетесь ли вы с ulimit max, - это запустить lsofи использовать grepили wc -lотслеживать все.
от
Я согласен. Это действительно сработало для моей реализации SCC Косараджу, исправив segfault в реализациях Python и C ++. <br/> Для своего MAC я выяснил возможный максимум через:
Rock
4
обратите внимание, что значение ulimit изменяется только для конкретной оболочки, в которой оно выполняется, чтобы вы случайно не изменили значение для всей вашей системы
Tanmay Garg
1
Я сделал это и получил ulimit -s 16384, однако после запуска у меня все еще была ошибка сегментации.
Sreehari R
@SreehariR Попробуйте еще больше увеличить. Однако это также может быть проблема с расширением python (если вы его используете), которое (этот другой ответ) [ stackoverflow.com/a/10035594/25891] предлагает, как отлаживать
Davide
18

Ошибка сегментации является общей, для этого есть много возможных причин:

  • Мало памяти
  • Неисправная оперативная память
  • Получение огромного набора данных из базы данных с помощью запроса (если размер извлеченных данных больше, чем память подкачки)
  • неправильный запрос / ошибочный код
  • имеющий длинный цикл (множественная рекурсия)
Садхиш
источник
3

Обновление ulimit сработало для моей реализации SCC Kosaraju, исправив segfault как в реализациях Python (Python segfault… кто знал!), Так и в реализациях C ++.

Для своего MAC я узнал возможный максимум через:

$ ulimit -s -H
65532
рок
источник
как обновить это значение? это значение в единицах какого типа?
Пабло
Если вы много ЗНАЕТЕ о том, какими должны быть ваши ограничения (и вы знаете, что ваша платформа никогда не изменится от Linux), вы можете использовать команду выполнения python, чтобы просто выполнить эту команду из вашего кода. Я лично добавил его в свой файл .bashrc.
трубят
2

Поиск Google нашел мне эту статью, и я не видел, чтобы обсуждалось следующее "личное решение".


Мое недавнее раздражение по поводу Python 3.7 в подсистеме Windows для Linux заключается в том, что на двух машинах с одной и той же библиотекой Pandas одна выдает мне, segmentation faultа другая сообщает предупреждение. Было непонятно, какая из них новее, но «переустановка» pandasрешает проблему.

Команда, которую я запускал на глючной машине.

conda install pandas

Дополнительные сведения: я запускал идентичные сценарии (синхронизированные через Git), и оба являются машиной Windows 10 с WSL + Anaconda. Вот скриншоты, чтобы понять причину. Кроме того, на машине, на которую pythonбудет Segmentation fault (core dumped)выдавать жалоба командная строка , Jupyter lab просто перезагружает ядро ​​каждый раз. Что еще хуже, никакого предупреждения не последовало.

введите описание изображения здесь


Обновления через несколько месяцев: я перестал размещать серверы Jupyter на компьютере с Windows. Теперь я использую WSL в Windows для получения удаленных портов, открытых на сервере Linux, и запуска всех моих заданий на удаленном компьютере Linux. Я ни разу не сталкивался с ошибками выполнения в течение многих месяцев :)

Llinfeng
источник
0

У меня возникла эта ошибка сегментации после обновления dlib на RPI. Я отследил стек, как это было предложено Шиплу Мокаддим выше, и остановился на библиотеке 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

Digitalf8
источник
-1

Похоже, у вас закончилась стековая память. Вы можете захотеть увеличить его, как сказал Давид. Чтобы сделать это в коде 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 на codeforces . Запускать его с PyPy немного сложнее .

Рустам А.
источник