2010-09-02 9 views
25

Sto usando matplotlib per generare molti grafici dei risultati di una simulazione numerica. Le trame sono utilizzati come fotogrammi di un video, e quindi sono la generazione di molti di loro chiamando ripetutamente una funzione simile a questa:Matlotlib Python: memoria non rilasciata quando si specifica la dimensione della figura

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() 

Il problema è che l'utilizzo della memoria del processo di pitone cresce di un un paio di megabyte con ogni chiamata a questa funzione. Per esempio se lo chiamo con questo ciclo:

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 

quindi l'utilizzo di ram cresce con il tempo a 600 MB. Se tuttavia commento la riga figure(figsize=(8,6)) nella definizione della funzione, l'utilizzo della ram rimane costante a 52 MB. (8,6) è la dimensione della cifra predefinita e in entrambi i casi vengono prodotte immagini identiche. Mi piacerebbe realizzare trame di dimensioni diverse dai miei dati numerici senza esaurire il ram. Come potrei costringere Python a liberare questa memoria?

Ho provato gc.collect() ogni ciclo per forzare la raccolta dei rifiuti, e ho provato f = gcf() per ottenere la cifra attuale e poi del f di eliminarlo, ma senza alcun risultato.

Sto eseguendo CPython 2.6.5 su 64 bit Ubuntu 10.04.

risposta

35

Dal docstring per pylab.figure:

In [313]: pylab.figure? 

Se si sta creando molte figure, fare che si esplicitamente chiamate "stretta" sulle le cifre non si sta utilizzando, perché questo permetterà pylab per correttamente pulire la memoria.

Quindi, forse, provare:

pylab.close()  # closes the current figure 
+0

che lo fa! Grazie mille. –

+2

Sì, 'clf' non cancella la figura o rilascia le sue risorse, la cancella solo. E 'f = gcf(); del f' cancella solo il riferimento appena creato, non cancella l'oggetto stesso. Questo è quello che ti serve per "chiudere". (+1) –

9

La chiusura di un dato è sicuramente un'opzione, tuttavia, ripetuto molte volte, questo è in termini di tempo. Quello che suggerisco è di avere un singolo oggetto figura persistente (tramite static function variable o come argomento di funzione aggiuntivo). Se tale oggetto è fig, la funzione chiamerà quindi fig.clf()prima del ogni ciclo di stampa.

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) 

Ecco valorizza la tempistica

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 
+1

Nizza. Ora mi è chiaro che con ogni chiamata a 'figure()' nel mio esempio originale stavo creando una nuova figura e non chiudendo quella vecchia. Oltre ad aggrapparsi a un riferimento, si potrebbe anche fornire l'argomento numero: 'figure (0, figsize = whatever)' per garantire che la stessa figura venisse utilizzata ogni volta. –

Problemi correlati