2010-09-02 11 views
25

Używam matplotlib do generowania wielu wykresów wyników symulacji numerycznej. Działki są wykorzystywane jako klatek filmu, a więc jestem generowania wielu z nich kilkakrotnie wywołanie funkcji podobny do tego:Python matplotlib: pamięć nie jest zwolniona przy określaniu rozmiaru rysunku

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

Problemem jest to, że użycie pamięci procesu Pythona rośnie przez kilka megabajtów przy każdym wywołaniu tej funkcji. Na przykład, jeśli zadzwonię do tej pętli:

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 

, a następnie wykorzystanie pamięci RAM rośnie z czasem do 600 MB. Jeśli jednak w definicji funkcji skomentuję linię figure(figsize=(8,6)), to użycie pamięci pozostaje stałe na poziomie 52 MB. (8,6) to domyślny rozmiar figury, a więc identyczne obrazy są tworzone w obu przypadkach. Chciałbym tworzyć wykresy o różnych rozmiarach z moich danych liczbowych bez wyczerpania pamięci RAM. Jak mogę zmusić Pythona do zwolnienia tej pamięci?

Próbowałem gc.collect() każdej pętli zmusić zbieranie śmieci, a próbowałem f = gcf() aby uzyskać aktualny rysunek, a następnie del f aby go usunąć, ale bezskutecznie.

Używam CPython 2.6.5 na 64-bitowym systemie Ubuntu 10.04.

Odpowiedz

35

Z docstring dla pylab.figure:

In [313]: pylab.figure? 

Jeśli tworzysz wiele danych liczbowych, należy pewno jawnie wywołać „zamknij” na dane nie są używane, ponieważ umożliwi to pylab prawidłowo wyczyść pamięć.

Więc może spróbuj:

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

To prawda! Dziękuję bardzo. –

+2

Tak, 'clf' nie usuwa figury ani nie zwalnia jej zasobów, tylko ją usuwa. Oraz 'f = gcf(); del f' usuwa tylko utworzoną referencję, nie usuwa samego obiektu figurki. Właśnie tego potrzebujesz "zamknąć". (+1) –

9

Zamknięcie postać jest zdecydowanie opcja jednak powtarzane wiele razy, jest to czasochłonne. To, co sugeruję, to posiadanie pojedynczego stałego obiektu liczbowego (poprzez static function variable lub jako dodatkowy argument funkcji). Jeśli ten obiekt to fig, funkcja będzie następnie wywoływać fig.clf()przed każdym cyklem drukowania.

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) 

Oto rozrządu wartości

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

Nice. Teraz jest dla mnie jasne, że przy każdym wywołaniu 'figure()' w moim oryginalnym przykładzie tworzyłem nową figurę i nie zamyślałem starej. Poza zawieszeniem na referencji można również podać argument liczby: 'figure (0, figsize = cokolwiek)', aby zapewnić, że za każdym razem używana jest ta sama liczba. –

Powiązane problemy