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_profiler
Die 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 № 1Um 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()