MemoryError lösen

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Benutzeravatar
microkernel
User
Beiträge: 271
Registriert: Mittwoch 10. Juni 2009, 17:27
Wohnort: Frankfurt
Kontaktdaten:

Hallo,

ich hab vor kurzen ein kleines Script geschrieben welches von jeder Datei auf meinen Computer eine MD5, SHA1 und eine SHA256 Hashsumme erstellt und diese in eine MySQL Datenbank einträgt. Danach sollen diese Hashsummen mit einer Datenbank verglichen werden in welcher Hashsummen von Malware eingetragen ist. Das Script welches die Hashsummen von mein Dateien erstellt sieht wie folgt aus:

Code: Alles auswählen

import hashlib
import sys
import os

import MySQLdb

def main():
    walker = os.walk(os.environ["SYSTEMDRIVE"] + os.sep)
    while True:
        try:
            curdir = walker.next()
        except StopIteration:
            break
        finally:
            for f in curdir[2]:
                insert(curdir[0], f)

def insert(path, fname):
    absolute = path + os.sep + fname
    
    try:
        content = open(absolute, "r").read()
        md5 = hashlib.md5(content).hexdigest()
        sha256 = hashlib.sha256(content).hexdigest()
        sha1 = hashlib.sha1(content).hexdigest()
    except IOError:
        md5 = sha256 = sha1 = ""
        
    cursor.execute("INSERT INTO files VALUES (%s, %s, %s, %s, %s)",
                   (fname, absolute, md5, sha256, sha1))
    connection.commit()    

if __name__ == "__main__":
    try:
        connection = MySQLdb.connect(
            "localhost",
            "root",
            "",
            "system")
    except:
        sys.stdout.write("Can not connect to MySQL database (adress: localhost, user: root, password: '', table: system)")
        sys.exit(0)
    cursor = connection.cursor()
    sys.stdout.write("Running... Pleas be patient")
    main()
Nun erhalte ich jedoch nach zirka 70.000 eingetragenen Datensätzen erscheint bei mir ein MemoryError. Mir ist bekannt was für ein Fehler das ist und was das bedeuted allerdings verstehe ich nicht warum dieser Fehler auftritt.
Kann mir da vielleicht jemand erklären warum dieser Fehler auftritt und wie ich ihn beheben kann?

Liebe Grüße
microkernel
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Hast du schonmal daran gedacht dass es Dateien auf deinem System geben könnte die nicht komplett in deinen Speicher passen?

Abgesehen davon dass dein Script wahrscheinlich nur auf CPython läuft ohne das Limit an geöffneten Dateien zu erreichen.
lunar

Dieser Fehler tritt nicht zufällig bei der Verarbeitung einer besonders großen Datei auf?

Dazu die üblichen Hinweise: Pfade setzt man mit "os.path.join()" zusammen, Dateien öffnet und schließt man mit der "with"-Anweisung, Ausnahmen konkret behandeln und nicht alle pauschal (kein "except" ohne Ausnahmespezifikation oder zumindest logging des Tracebacks), usw. Und was in Gottes Namen hast Du Dir den bei "main()" gedacht?!
Py-Prog
User
Beiträge: 673
Registriert: Dienstag 16. Februar 2010, 17:52
Wohnort: G:\ermany

DasIch hat geschrieben:Hast du schonmal daran gedacht dass es Dateien auf deinem System geben könnte die nicht komplett in deinen Speicher passen?
Na und, Der DS (Lite) kann auch eine über ein GB große datei offnen, und der hat auch nur 4 MB RAM. Oder liegt das an dem Flash speicher?

@microkernel jetzt weiß doch jeder den inhalt der Datei, jetzt braucht man nur noch eine Virus der die Festplatte nach dem Inhalt durchsucht und die Datei Löscht. :D
Technik ist: wenn alles funktioniert und keiner weiß warum.
Wer Rechtschreibfehler findet darf sie behalten.
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Py-Prog hat geschrieben:
DasIch hat geschrieben:Hast du schonmal daran gedacht dass es Dateien auf deinem System geben könnte die nicht komplett in deinen Speicher passen?
Na und, Der DS (Lite) kann auch eine über ein GB große datei offnen, und der hat auch nur 4 MB RAM. :D (Echt kein Scherz)
Wieso sollte er es auch nicht können?

Irgendwie hab ich ja das Gefühl es steht ums Textverständnis im Allgemeinen deutlich schlechter als von Pisa ermittelt.
Py-Prog
User
Beiträge: 673
Registriert: Dienstag 16. Februar 2010, 17:52
Wohnort: G:\ermany

Wieso sollte dann ein PC mit 2 GB ram keine 2,35 GB Datei Öffnen Können?
Technik ist: wenn alles funktioniert und keiner weiß warum.
Wer Rechtschreibfehler findet darf sie behalten.
BlackJack

@Py-Prog: Es geht nicht darum ob die Datei geöffnet werden kann, sondern darum sie nach dem Öffnen komplett in den Speicher zu lesen. Und Du wirst doch verstehen das der DS keine 1 GB-Datei komplett in nur 4 MB Speicher einlesen kann, oder!? Genau so wenig kann ein PC eine deutlich grössere Datei als Hauptspeicher vorhanden ist, in selbigen einlesen.

In beiden Fällen kann man aber kleinere Teile der Datei einlesen und verarbeiten. Und das kann man so oft machen, bis man alle Daten der Datei einmal im Speicher hatte und die Prüfsumme mit den Daten aktualisiert hat um so eine Prüfsumme über die gesamte Datei zu bekommen.
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Mal was zum Code:
Wenn ich nichts uebersehe liesse sich

Code: Alles auswählen

def main():
    walker = os.walk(os.environ["SYSTEMDRIVE"] + os.sep)
    while True:
        try:
            curdir = walker.next()
        except StopIteration:
            break
        finally:
            for f in curdir[2]:
                insert(curdir[0], f)
als

Code: Alles auswählen

def main():
    walker = os.walk(os.environ["SYSTEMDRIVE"])
    for dir, _, files in walker:
        for f in files:
            insert(dir, f)
schreiben.
Benutzeravatar
microkernel
User
Beiträge: 271
Registriert: Mittwoch 10. Juni 2009, 17:27
Wohnort: Frankfurt
Kontaktdaten:

@cofi und lunar
Oh gott :D manchmal denke ich etwas umständlich :mrgreen:

Ich hab das eigentliche Problem jetzt so gelöst:

Code: Alles auswählen

  
[...]
try:
    with open(absolute, "r") as f:           
        md5 = hashlib.md5()
        sha256 = hashlib.sha256()    
        sha1 = hashlib.sha1() 
        content = 1           
        while content != "":
            content = f.read(1048576 * 500) # 500 MB
            md5.update(content)
            sha256.update(content)
            sha1.update(content)                
            
    md5 = md5.hexdigest()
    sha256 = sha256.hexdigest()
    sha1 = sha1.hexdigest()
except IOError:
    md5 = sha256 = sha1 = ""
[...]
Benutzeravatar
microkernel
User
Beiträge: 271
Registriert: Mittwoch 10. Juni 2009, 17:27
Wohnort: Frankfurt
Kontaktdaten:

Hallo,

ich hab jetzt noch eine kleine Frage: Wie könnte ich den Ablauf beschleunigen? Könnte ich vielleicht eine C-Lib für die Hashsummen berechnung nehmen? Threads währen hier doch wenig hilfreich, oder?

Lg
microkernel
lunar

Du kannst dieses Programm nicht wesentlich beschleunigen, denn die Festplatte ist hier der Flaschenhals. Im Übrigen ist hashlib bereits in C implementiert.
Py-Prog
User
Beiträge: 673
Registriert: Dienstag 16. Februar 2010, 17:52
Wohnort: G:\ermany

Du kaufst dir etwas Flüssigstickstoff um damit die übertaktete CPU zu kühlen. :D :D :D

Oder du kompilierst den Code, dann wird es normal auch schneller, aber selbst dann wird es noch einige Zeit dauern. Da hilft dann nur noch bessere Hardware.
Technik ist: wenn alles funktioniert und keiner weiß warum.
Wer Rechtschreibfehler findet darf sie behalten.
Benutzeravatar
HerrHagen
User
Beiträge: 430
Registriert: Freitag 6. Juni 2008, 19:07

Du nimmst dir einen schneller zu berechnenden Hash-Wert. Du musst ja bei deiner Anwendung keine kryptographischen Anforderungen erfüllen.
Py-Prog
User
Beiträge: 673
Registriert: Dienstag 16. Februar 2010, 17:52
Wohnort: G:\ermany

HerrHagen hat geschrieben:Du nimmst dir einen schneller zu berechnenden Hash-Wert. Du musst ja bei deiner Anwendung keine kryptographischen Anforderungen erfüllen.
Und was ist wenn die Datenbank aber genau soeinen Hash braucht?
Technik ist: wenn alles funktioniert und keiner weiß warum.
Wer Rechtschreibfehler findet darf sie behalten.
Benutzeravatar
HerrHagen
User
Beiträge: 430
Registriert: Freitag 6. Juni 2008, 19:07

Warum sollte das so sein? Ich denke es geht darum Malware zu idendifizieren? In eine Datenbank kann man alles mögliche speichern.
Py-Prog
User
Beiträge: 673
Registriert: Dienstag 16. Februar 2010, 17:52
Wohnort: G:\ermany

Ich meine die Datenbank mit der es vergleichen will, die wird er ja wohl nicht selber erstellt haben.
Technik ist: wenn alles funktioniert und keiner weiß warum.
Wer Rechtschreibfehler findet darf sie behalten.
Benutzeravatar
microkernel
User
Beiträge: 271
Registriert: Mittwoch 10. Juni 2009, 17:27
Wohnort: Frankfurt
Kontaktdaten:

Py-Prog hat geschrieben:Ich meine die Datenbank mit der es vergleichen will, die wird er ja wohl nicht selber erstellt haben.
Da stimmt. :? Mir stehen nur SHA256, SHA1 und MD5 Hashsummen zum vergleichen zur Verfügung.
Py-Prog hat geschrieben:Oder du kompilierst den Code, dann wird es normal auch schneller, aber selbst dann wird es noch einige Zeit dauern. Da hilft dann nur noch bessere Hardware.
Ich dachte eigentlich immer das kompilierte Python Dateien nur schneller starten jedoch nicht schneller ablaufen (?)
Dauerbaustelle
User
Beiträge: 996
Registriert: Mittwoch 9. Januar 2008, 13:48

microkernel hat geschrieben:
Py-Prog hat geschrieben:Oder du kompilierst den Code, dann wird es normal auch schneller, aber selbst dann wird es noch einige Zeit dauern. Da hilft dann nur noch bessere Hardware.
Ich dachte eigentlich immer das kompilierte Python Dateien nur schneller starten jedoch nicht schneller ablaufen (?)
Kommt auf die Art der Kompilierung an.

CPython "kompiliert" Python-Programme erst mal zu Bytecode und interpretiert den dann. Der Bytecode für die Datei "foo.py" wird in "foo.pyc" gespeichert. Existiert eine solche Bytecode-Datei bereits bei der Ausführung von "foo.py" und ist sie nicht veraltet, überspringt CPython den Zu-Bytecode-Übersetz-Vorgang und fängt direkt an, den Bytecode zu interpretieren. Deine Annahme war also korrekt.

Es ist allerdings auch möglich, Python nach C zu übersetzen (Cython) oder nach C++ (Shedskin) oder nach JVM-Bytecode (Jython) oder nach .NET-Bytecode (IronPython) oder mit PyPy zur Laufzeit zu kompilieren (mit dem JIT) usf. Zumindest bei Cython, Shedskin und PyPy ist die Chance hoch, dass der Code dann schneller abläuft, weil bei der Kompilierung natürlich Optimierungen gemacht werden können, die CPython nicht macht.

Das tut aber alles überhaupt nichts zur Sache, weil ``hashlib`` sowieso schon in C geschrieben und der Flaschenhals eh die Festplatte ist, wie lunar bereits angemerkt hat.
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

microkernel hat geschrieben:Mir stehen nur SHA256, SHA1 und MD5 Hashsummen zum vergleichen zur Verfügung.
Die einfachste Moeglichkeit schneller zu sein, ist es weniger zu machen .. warum also 3 Hashes berechnen?

In dem Fall könnte es aber natuerlich keinen grossen Einfluss haben. Erzaehl uns doch ein wenig mehr ueber das Ziel und die Beschraenkungen unter denen du arbeiten musst.
Py-Prog
User
Beiträge: 673
Registriert: Dienstag 16. Februar 2010, 17:52
Wohnort: G:\ermany

Ich weiß nicht ob es bei Linux oder Mac geht aber bei Windows kann man über den Taskmanager die Priorität eines Prozesses einstellen das geht auch mit einem Batch-skript. (Wenn das Konsolen Fenster stört mit dem Bat_to_Exe_Converter unsichtbar machen.)
Technik ist: wenn alles funktioniert und keiner weiß warum.
Wer Rechtschreibfehler findet darf sie behalten.
Antworten