Ich versuche, den Ursprung eines bösen Speicherverlust in einem Python/NumPy-Programm mit C/Cython-Erweiterungen und multiprocessing
zu finden.Debugging eines Python/NumPy Speicherlecks
Jeder Unterprozess verarbeitet eine Liste von Bildern, und für jeden von ihnen sendet das Ausgabe-Array (das normalerweise etwa 200-300MB groß ist) über eine Queue
an den Hauptprozess. Ziemlich Standard-Karte/Setup reduzieren.
Wie Sie sich vorstellen können, kann ein Speicherleck ganormous Proportionen mit Arrays so groß nehmen, und mehrere Prozesse glücklich gehen über 20 GB RAM, wenn sie nur 5-6GB benötigen würde ... ist ärgerlich. meine Erweiterungen für Speicherlecks
Ich habe versucht, eine Debug-Version von Python durch Valgrind ausgeführt wird, und Quadruple-geprüft, aber nichts gefunden.
Ich habe meinen Python-Code überprüft, um Verweise auf meine Arrays zu erzeugen, und habe auch NumPy's allocation tracker verwendet, um zu überprüfen, ob meine Arrays tatsächlich freigegeben wurden. Sie sind.
Das letzte, was ich GDB auf einem meiner Prozesse tat, war aufstecken (das Bad Boy ist bei 27GB RAM und Zählen jetzt ausgeführt) und einen großen Teil des Haufens auf die Platte Dumping. Zu meiner großen Überraschung war die gedumpte Datei voller Nullen! Ungefähr 7G Nullen.
Ist dies ein Standard-Speicherzuordnungsverhalten in Python/NumPy? Habe ich etwas Offensichtliches vermisst, das erklären würde, dass so viel Speicher für nichts genutzt wird? Wie kann ich den Speicher richtig verwalten?
EDIT: Für das Protokoll, ich bin mit NumPy 1.7.1 und Python 2.7.3.
EDIT 2: Ich habe Überwachung des Prozesses mit strace
, und es scheint, dass es auf die Erhöhung der Bruchstelle eines jeden Prozesses hält (mit dem brk()
syscall).
Gibt CPython tatsächlich Speicher ordnungsgemäß frei? Was ist mit C-Erweiterungen, NumPy-Arrays? Wer entscheidet wann brk()
, ist es Python selbst oder ist es eine zugrunde liegende Bibliothek (libc
, ...)?
Unten ist ein Beispiel für Strace-Log mit Kommentaren von einer Iteration (d. H. Ein Eingabebildsatz). Beachten Sie, dass der Breakpoint weiter zunimmt, aber ich habe (mit objgraph
) sichergestellt, dass keine sinnvollen NumPy-Arrays im Python-Interpreter enthalten sind.
# Reading .inf files with metadata
# Pretty small, no brk()
open("1_tif_all/AIR00642_1.inf", O_RDONLY) = 6
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f9387fff000
munmap(0x7f9387fff000, 4096) = 0
open("1_tif_all/AIR00642_2.inf", O_RDONLY) = 6
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f9387fff000
munmap(0x7f9387fff000, 4096) = 0
open("1_tif_all/AIR00642_3.inf", O_RDONLY) = 6
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f9387fff000
munmap(0x7f9387fff000, 4096) = 0
open("1_tif_all/AIR00642_4.inf", O_RDONLY) = 6
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f9387fff000
munmap(0x7f9387fff000, 4096) = 0
# This is where I'm starting the heavy processing
write(2, "[INFO/MapProcess-1] Shot 642: Da"..., 68) = 68
write(2, "[INFO/MapProcess-1] Shot 642: Vi"..., 103) = 103
write(2, "[INFO/MapProcess-1] Shot 642: Re"..., 66) = 66
# I'm opening a .tif image (752 x 480, 8-bit, 1 channel)
open("1_tif_all/AIR00642_3.tif", O_RDONLY) = 6
read(6, "II*\0JC\4\0", 8) = 8
mmap(NULL, 279600, PROT_READ, MAP_SHARED, 6, 0) = 0x7f9387fbb000
munmap(0x7f9387fbb000, 279600) = 0
write(2, "[INFO/MapProcess-1] Shot 642: Pr"..., 53) = 53
# Another .tif
open("1_tif_all/AIR00642_4.tif", O_RDONLY) = 6
read(6, "II*\0\266\374\3\0", 8) = 8
mmap(NULL, 261532, PROT_READ, MAP_SHARED, 6, 0) = 0x7f9387fc0000
munmap(0x7f9387fc0000, 261532) = 0
write(2, "[INFO/MapProcess-1] Shot 642: Pr"..., 51) = 51
brk(0x1aea97000) = 0x1aea97000
# Another .tif
open("1_tif_all/AIR00642_1.tif", O_RDONLY) = 6
read(6, "II*\0\220\253\4\0", 8) = 8
mmap(NULL, 306294, PROT_READ, MAP_SHARED, 6, 0) = 0x7f9387fb5000
munmap(0x7f9387fb5000, 306294) = 0
brk(0x1af309000) = 0x1af309000
write(2, "[INFO/MapProcess-1] Shot 642: Pr"..., 53) = 53
brk(0x1b03da000) = 0x1b03da000
# Another .tif
open("1_tif_all/AIR00642_2.tif", O_RDONLY) = 6
mmap(NULL, 345726, PROT_READ, MAP_SHARED, 6, 0) = 0x7f9387fab000
munmap(0x7f9387fab000, 345726) = 0
brk(0x1b0c42000) = 0x1b0c42000
write(2, "[INFO/MapProcess-1] Shot 642: Pr"..., 51) = 51
# I'm done reading my images
write(2, "[INFO/MapProcess-1] Shot 642: Fi"..., 72) = 72
# Allocating some more arrays for additional variables
# Increases by about 8M at a time
brk(0x1b1453000) = 0x1b1453000
brk(0x1b1c63000) = 0x1b1c63000
brk(0x1b2473000) = 0x1b2473000
brk(0x1b2c84000) = 0x1b2c84000
brk(0x1b3494000) = 0x1b3494000
brk(0x1b3ca5000) = 0x1b3ca5000
# What are these mmap calls doing here?
mmap(NULL, 270594048, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f9377df1000
mmap(NULL, 270594048, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f9367be2000
mmap(NULL, 270594048, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f93579d3000
mmap(NULL, 270594048, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f93477c4000
mmap(NULL, 270594048, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f93375b5000
munmap(0x7f93579d3000, 270594048) = 0
munmap(0x7f93477c4000, 270594048) = 0
mmap(NULL, 270594048, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f93579d3000
munmap(0x7f93375b5000, 270594048) = 0
mmap(NULL, 50737152, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f9354970000
munmap(0x7f9354970000, 50737152) = 0
brk(0x1b4cc6000) = 0x1b4cc6000
brk(0x1b5ce7000) = 0x1b5ce7000
EDIT 3:Is freeing handled differently for small/large numpy arrays? relevant sein können. Ich bin zunehmend davon überzeugt, dass ich einfach zu viele Arrays verteile, die nicht an das System weitergegeben werden, weil es sich tatsächlich um Standardverhalten handelt. Ich werde versuchen, meine Arrays vorher zuzuweisen und sie bei Bedarf wiederzuverwenden.
Was verwenden Sie zum Lesen der Bilddateien? Ich hatte Speicherverlust Probleme mit PIL 'Image' Objekte in der Vergangenheit –
Ich verwende die PyLibTiff Bindings. Und ich habe das gelöst, sehe meine Antwort! –