Was verursacht einen Python-Segmentierungsfehler?

82

Ich implementiere Kosarajus SCC-Diagrammsuchalgorithmus (Strong Connected Component) in Python.

Das Programm läuft hervorragend auf kleinen Datenmengen, aber wenn ich es auf einem super großen Diagramm (mehr als 800.000 Knoten) ausführe, heißt es "Segmentierungsfehler".

Was könnte die Ursache dafür sein? Vielen Dank!


Zusätzliche Informationen: Zuerst habe ich diesen Fehler beim Ausführen des sehr großen Datensatzes erhalten:

"RuntimeError: maximum recursion depth exceeded in cmp"

Dann setze ich das Rekursionslimit mit zurück

sys.setrecursionlimit(50000)

habe aber einen 'Segmentierungsfehler'

Glauben Sie mir, es ist keine Endlosschleife, sie läuft korrekt mit relativ kleinen Daten. Ist es möglich, dass das Programm die Ressourcen erschöpft hat?

Xiaolong
quelle
10
Abhijit
2
Läuft dies in reinem Python oder verwenden Sie ein C-Erweiterungsmodul? Wenn es reines Python ist, dann ist es ein Fehler und Glückwunsch. Wenn Sie ein Wechselstrommodul verwenden, kommt der Segfault wahrscheinlich von dort.
Aaronasterling
Es ist Pure Python. Das Programm läuft großartig mit relativ kleinen Datenmengen und hat mich denken lassen, dass der Code korrekt ist.
Xiaolong
Laut der Python-Dokumentation:
James Thiele
2
Laut Python-Dokumentation :::::: Das höchstmögliche Limit ist plattformabhängig. Ein Benutzer muss möglicherweise das Limit höher festlegen, wenn er ein Programm hat, das eine tiefe Rekursion erfordert, und eine Plattform, die ein höheres Limit unterstützt. Dies sollte mit Vorsicht erfolgen, da ein zu hohes Limit zu einem Absturz führen kann. :::::: Sie haben kein Betriebssystem angegeben. Der Hinweis auf einen Absturz kann einen Segmentierungsfehler auf Ihrem Betriebssystem bedeuten . Versuchen Sie es mit einem kleineren Stapel. Aber IIRC, der von Ihnen verwendete Algorithmus, legt den gesamten SSC auf den Stapel, sodass Ihnen möglicherweise der Stapel ausgeht.
James Thiele

Antworten:

80

Dies geschieht, wenn eine Python- Erweiterung (in C geschrieben) versucht, auf einen Speicher außerhalb der Reichweite zuzugreifen.

Sie können es auf folgende Arten verfolgen.

  • Fügen Sie sys.settracein der ersten Zeile des Codes hinzu.
  • Verwenden Sie gdbwie in dieser Antwort von Mark beschrieben . An der Eingabeaufforderung

    gdb python
    (gdb) run /path/to/script.py
    ## wait for segfault ##
    (gdb) backtrace
    ## stack trace of the c code
    
Shiplu Mokaddim
quelle
2
Danke, aber mein Code ist reines Python. Macht es einen Unterschied?
Xiaolong
Überprüfen Sie, welche Python-Module Sie verwenden? Einige Module sind in Python geschrieben, andere in C. Ich denke, Sie müssen einen Fehler melden.
Shiplu Mokaddim
1
ähnlich, auch hilfreich: Das Trace- Modul von stdlib hat mir nur geholfen, einem Segmentierungsfehler auf einem Staging-Server auf den Grund zu gehen, ohne eine neue Abhängigkeit zu installieren und ohne Code zu ändern.
Driftcatcher
3
unter OSX Sierra wurde gdb
kthouz
51

Ich verstehe, dass Sie Ihr Problem gelöst haben, aber für andere, die diesen Thread lesen, ist hier die Antwort: Sie müssen den Stapel erhöhen, den Ihr Betriebssystem für den Python-Prozess zuweist.

Die Vorgehensweise hängt vom Betriebssystem ab. Unter Linux können Sie mit dem Befehl ulimit -sIhren aktuellen Wert überprüfen und mit erhöhenulimit -s <new_value>

Versuchen Sie, den vorherigen Wert zu verdoppeln, und verdoppeln Sie ihn weiter, wenn er nicht funktioniert, bis Sie einen finden, der nicht mehr über genügend Speicher verfügt.

Davide
quelle
Eine gute Möglichkeit, um zu überprüfen, ob Sie auf ein ulimit max stoßen, besteht darin, alles auszuführen lsofund zu verwenden grepoder wc -lden Überblick zu behalten.
17:57
Ich stimme zu. Dies funktionierte tatsächlich für die SCC-Implementierung meines Kosaraju, indem der Segfault sowohl bei Python- als auch bei C ++ - Implementierungen behoben wurde. <br/> Für meinen MAC habe ich das mögliche Maximum herausgefunden über:
Rock
4
Beachten Sie, dass der ulimit-Wert nur für die bestimmte Shell geändert wird, in der er ausgeführt wird, damit Sie den Wert für Ihr gesamtes System nicht versehentlich ändern
Tanmay Garg
1
Ich tat dies und endete mit ulimit -s 16384, aber nach dem Ausführen bekam ich immer noch einen Segmentierungsfehler.
Sreehari R
@SreehariR Versuchen Sie es noch weiter zu erhöhen. Es könnte jedoch auch ein Problem mit einer Python-Erweiterung sein (falls Sie eine verwenden), die (diese andere Antwort) [ stackoverflow.com/a/10035594/25891] vorschlägt, wie man debuggt
Davide
18

Der Segmentierungsfehler ist generisch. Dafür gibt es viele mögliche Gründe:

  • Wenig Speicher
  • Fehlerhafter RAM-Speicher
  • Abrufen eines großen Datensatzes aus der Datenbank mithilfe einer Abfrage (wenn die Größe der abgerufenen Daten mehr als Swap Mem beträgt)
  • falscher Abfrage- / Buggy-Code
  • mit langer Schleife (Mehrfachrekursion)
Sadheesh
quelle
2

Das Aktualisieren des ulimit funktionierte für die SCC-Implementierung meines Kosaraju, indem der Segfault sowohl bei Python- (Python-Segfault .. wer wusste!) Als auch bei C ++ - Implementierungen behoben wurde.

Für meinen MAC habe ich das mögliche Maximum herausgefunden über:

$ ulimit -s -H
65532
Felsen
quelle
Wie aktualisiere ich diesen Wert? ist dieser Wert in welcher Art von Einheit?
Pablo
2

Die Google-Suche hat mir diesen Artikel gefunden, und ich habe die folgende "persönliche Lösung" nicht besprochen.


Mein jüngster Ärger mit Python 3.7 unter Windows Subsystem für Linux ist folgender: Auf zwei Computern mit derselben Pandas-Bibliothek gibt einer segmentation faultund der andere eine Warnung aus. Es war nicht klar, welches neuer war, aber "Neuinstallation" pandaslöst das Problem.

Befehl, den ich auf dem Buggy ausgeführt habe.

conda install pandas

Weitere Details: Ich habe identische Skripte ausgeführt (über Git synchronisiert) und beide sind Windows 10-Computer mit WSL + Anaconda. Hier gehen die Screenshots, um den Fall zu machen. Auf dem Computer, über den sich die Befehlszeile pythonbeschwert Segmentation fault (core dumped), startet Jupyter Lab den Kernel einfach jedes Mal neu. Schlimmer noch, es wurde überhaupt keine Warnung gegeben.

Geben Sie hier die Bildbeschreibung ein


Updates einige Monate später: Ich habe das Hosting von Jupyter-Servern auf einem Windows-Computer beendet. Ich verwende jetzt WSL unter Windows, um auf einem Linux-Server geöffnete Remote-Ports abzurufen und alle meine Jobs auf dem Remote-Linux-Computer auszuführen. Ich habe seit einigen Monaten keinen Ausführungsfehler mehr festgestellt :)

llinfeng
quelle
0

Ich habe diesen Segmentierungsfehler nach dem Upgrade von dlib auf RPI festgestellt. Ich habe den Stapel zurückverfolgt, wie oben von Shiplu Mokaddim vorgeschlagen, und er hat sich in einer OpenBLAS-Bibliothek niedergelassen.

Da OpenBLAS auch Multithread-fähig ist, multipliziert die Verwendung in einer Anwendung mit mehreren Threads die Threads exponentiell bis zum Segmentierungsfehler. Stellen Sie OpenBlas für Multithread-Anwendungen auf den Single-Thread-Modus ein.

Weisen Sie OpenBLAS in einer virtuellen Python-Umgebung an, nur einen einzigen Thread zu verwenden, indem Sie Folgendes bearbeiten:

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

und hinzufügen:

    export OPENBLAS_NUM_THREADS=1 
    export OPENBLAS_MAIN_FREE=1

Nach dem Neustart konnte ich alle meine Bilderkennungs-Apps auf rpi3b ausführen, die zuvor abstürzten.

Referenz: https://github.com/ageitgey/face_recognition/issues/294

Digitalf8
quelle
-1

Sieht so aus, als hätten Sie keinen Stapelspeicher mehr. Vielleicht möchten Sie es erhöhen, wie Davide sagte. Um dies in Python-Code zu tun, müssten Sie "main ()" mithilfe von Threading ausführen:

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()

Quelle: c1729s Beitrag über Codeforces . Das Ausführen mit PyPy ist etwas schwieriger .

Rustam A.
quelle