/ / numpy.ndarray-Objekte werden nicht aufgesammelt - Python, Speicherverwaltung, Speicherlecks, Speicherbereinigung, Speicherprofilierung

numpy.ndarray-Objekte werden nicht aufgesammelt - Python, Speicherverwaltung, Speicherlecks, Speicherbereinigung, Speicherprofilierung

Bei dem Versuch, einige Speicherverluste in den Python-Bindungen für einige C / C ++ - Funktionen zu verfeinern, stieß ich auf ein seltsames Verhalten bezüglich der Speicherbereinigung von Numpy Arrays.

Ich habe einige vereinfachte Fälle erstellt, um das Verhalten besser erklären zu können. Der Code wurde mit der memory_profilerDie Ausgabe von dem folgt unmittelbar danach. Es scheint, dass die Speicherbereinigung von Python bei NumPy-Arrays nicht wie erwartet funktioniert:

# File deallocate_ndarray.py
@profile
def ndarray_deletion():
import numpy as np
from gc import collect
buf = "abcdefghijklmnopqrstuvwxyz" * 10000
arr = np.frombuffer(buf)
del arr
del buf
collect()
y = [i**2 for i in xrange(10000)]
del y
collect()

if __name__=="__main__":
ndarray_deletion()

Mit dem folgenden Befehl habe ich das aufgerufen memory_profiler:

python -m memory_profiler deallocate_ndarray.py

Das habe ich bekommen:

Filename: deallocate_ndarray.py
Line #    Mem usage    Increment   Line Contents
================================================
5   10.379 MiB    0.000 MiB   @profile
6                             def ndarray_deletion():
7   17.746 MiB    7.367 MiB       import numpy as np
8   17.746 MiB    0.000 MiB       from gc import collect
9   17.996 MiB    0.250 MiB       buf = "abcdefghijklmnopqrstuvwxyz" * 10000
10   18.004 MiB    0.008 MiB       arr = np.frombuffer(buf)
11   18.004 MiB    0.000 MiB       del arr
12   18.004 MiB    0.000 MiB       del buf
13   18.004 MiB    0.000 MiB       collect()
14   18.359 MiB    0.355 MiB       y = [i**2 for i in xrange(10000)]
15   18.359 MiB    0.000 MiB       del y
16   18.359 MiB    0.000 MiB       collect()

Ich verstehe nicht, warum auch die erzwungenen Anrufe dazu führen collect Reduzieren Sie den Speicherbedarf des Programms nicht durchetwas Speicher freigeben. Selbst wenn sich Numpy-Arrays aufgrund der zugrundeliegenden C-Konstrukte nicht normal verhalten, warum wird dann nicht die Liste (die reiner Python ist) Müll gesammelt?

ich weiß das del ruft den Basiswert nicht direkt auf __del__ Methode, aber Sie werden das alle merken del Anweisungen im Code enden tatsächlichdie Referenzzählung der entsprechenden Objekte auf Null (wodurch sie für die Müllsammlung AFAIK geeignet sind). Normalerweise würde ich erwarten, dass ein negativer Eintrag in der Inkrementierspalte angezeigt wird, wenn ein Objekt eine Garbage Collection durchläuft. Kann jemand etwas Licht auf das werfen, was hier los ist?

HINWEIS: Dieser Test wurde unter OS X 10.10.4, Python 2.7.10 (Conda), Numpy 1.9.2 (Conda), Memory Profiler 0.33 (Conda-Binstar), Psutil 2.2.1 (Conda) ausgeführt.

Antworten:

3 für die Antwort № 1

Um den Speicherabfall zu sehen, musste ich die Größe des Puffers um einige Größenordnungen vergrößern. Vielleicht ist die Größe zu klein memory_profiler Um die Änderung zu erkennen (es fragt das Betriebssystem ab, daher sind die Messungen nicht sehr genau) oder es ist zu klein, als dass der Python-Garbage Collector sich darum kümmern könnte, ich weiß es nicht.

Ersetzen Sie beispielsweise 10000 durch 100000000 im Faktor buf Erträge

Line #    Mem usage    Increment   Line Contents
================================================
21   10.289 MiB    0.000 MiB   @profile
22                             def ndarray_deletion():
23   17.309 MiB    7.020 MiB       import numpy as np
24   17.309 MiB    0.000 MiB       from gc import collect
25 2496.863 MiB 2479.555 MiB       buf = "abcdefghijklmnopqrstuvwxyz" * 100000000
26 2496.867 MiB    0.004 MiB       arr = np.frombuffer(buf)
27 2496.867 MiB    0.000 MiB       del arr
28   17.312 MiB -2479.555 MiB       del buf
29   17.312 MiB    0.000 MiB       collect()
30   17.719 MiB    0.406 MiB       y = [i**2 for i in xrange(10000)]
31   17.719 MiB    0.000 MiB       del y
32   17.719 MiB    0.000 MiB       collect()