Frage Python matplotlib: Speicher wird nicht freigegeben, wenn die Bildgröße angegeben wird


Ich verwende Matplotlib, um viele Diagramme der Ergebnisse einer numerischen Simulation zu erstellen. Die Plots werden als Frames in einem Video verwendet. Daher erzeuge ich viele von ihnen, indem ich wiederholt eine Funktion ähnlich der folgenden anrufe:

from pylab import *

def plot_density(filename,i,t,psi_Na):  
    figure(figsize=(8,6))
    imshow(abs(psi_Na)**2,origin = 'lower')
    savefig(filename + '_%04d.png'%i)
    clf()

Das Problem ist, dass die Speicherauslastung des Python-Prozesses bei jedem Aufruf dieser Funktion um einige Megabyte anwächst. Zum Beispiel, wenn ich es mit dieser Schleife anrufe:

if __name__ == "__main__":
    x = linspace(-6e-6,6e-6,128,endpoint=False)
    y = linspace(-6e-6,6e-6,128,endpoint=False)
    X,Y = meshgrid(x,y)
    k = 1000000
    omega = 200
    times = linspace(0,100e-3,100,endpoint=False)
    for i,t in enumerate(times):
        psi_Na = sin(k*X-omega*t)
        plot_density('wavefunction',i,t,psi_Na)
        print i

Dann wächst die Ram-Nutzung mit der Zeit auf 600MB. Wenn ich jedoch die Zeile auskommentiere figure(figsize=(8,6)) In der Funktionsdefinition bleibt die RAM-Auslastung konstant bei 52 MB. (8,6) ist die Standardfigurgröße und so werden in beiden Fällen identische Bilder erzeugt. Ich würde gerne aus meinen numerischen Daten Plots unterschiedlicher Größe machen, ohne den Ram zu verlieren. Wie kann ich Python zwingen, diesen Speicher freizugeben?

ich habe es versucht gc.collect() Jede Schleife, um Garbage Collection zu erzwingen, und ich habe es versucht f = gcf() um die aktuelle Zahl zu bekommen und dann del f um es zu löschen, aber ohne Erfolg.

Ich benutze CPython 2.6.5 auf 64-Bit Ubuntu 10.04.


25
2017-09-02 03:08


Ursprung


Antworten:


Aus dem Docstring für pylab.figure:

In [313]: pylab.figure?

Wenn Sie viele Figuren erstellen, machen Sie   sicher, dass du explizit "close" anrufst   die Zahlen, die du nicht benutzt, weil   Dies aktiviert pylab korrekt   bereinige den Speicher.

Also versuche vielleicht:

pylab.close()     # closes the current figure

35
2017-09-02 03:17



Das Schließen einer Figur ist definitiv eine Option, die jedoch oft wiederholt wird, dies ist zeitaufwendig. Was ich vorschlage, ist ein einziges persistentes Figurenobjekt (via statische Funktionsvariableoder als zusätzliches Funktionsargument). Wenn dieses Objekt ist fig, ruft die Funktion dann auf fig.clf()  Vor jeder Plottzyklus.

from matplotlib import pylab as pl
import numpy as np

TIMES = 10
x = np.linspace(-10, 10, 100)
y = np.sin(x)
def withClose():
    def plotStuff(i):
        fig = pl.figure()
        pl.plot(x, y + x * i, '-k')
        pl.savefig('withClose_%03d.png'%i)
        pl.close(fig)
    for i in range(TIMES):
        plotStuff(i)


def withCLF():
    def plotStuff(i):
        if plotStuff.fig is None:
            plotStuff.fig = pl.figure()
        pl.clf()
        pl.plot(x, y + x * i, '-')
        pl.savefig('withCLF_%03d.png'%i)
    plotStuff.fig = None

    for i in range(TIMES):
        plotStuff(i)

Hier sind die Timing-Werte

In [7]: %timeit withClose()
1 loops, best of 3: 3.05 s per loop

In [8]: %timeit withCLF()
1 loops, best of 3: 2.24 s per loop

9
2017-12-14 09:03