2011-08-19 12 views
9

Używam aplikacji django, która zawiera matplotlib i pozwala użytkownikowi określić osie wykresu. Może to spowodować "Błąd przepełnienia: przekroczenie Agg"Błędy Matplotlib powodują wyciek pamięci. Jak mogę zwolnić tę pamięć?

Kiedy to się stanie, do 100 MB pamięci RAM zostanie przywiązany. Zwykle zwalniam tę pamięć przy użyciu fig.gcf(), plot.close() i gc.collect(), ale pamięć skojarzona z błędem nie wydaje się być związana z obiektem wydruku.

Czy ktoś wie, jak mogę zwolnić tę pamięć?

Dzięki.

Oto kod, który podaje mi błąd złożoności Agg.

import matplotlib 
matplotlib.use('Agg') 
import matplotlib.pyplot as plt 
import numpy as np  
import gc 

a = np.arange(1000000) 
b = np.random.randn(1000000) 

fig = plt.figure(num=1, dpi=100, facecolor='w', edgecolor='w') 
fig.set_size_inches(10,7) 
ax = fig.add_subplot(111) 
ax.plot(a, b) 

fig.savefig('yourdesktop/random.png') # code gives me an error here 

fig.clf() # normally I use these lines to release the memory 
plt.close() 
del a, b 
gc.collect() 

Odpowiedz

9

Zakładam, że możesz uruchomić kod, który wysłałeś co najmniej raz. Problem pojawia się tylko po uruchomieniu wysłanego kodu wiele razy. Poprawny?

Jeśli tak, to unikaj problemu, nie określając źródła problemu. Może to jest złe, ale działa to szczypto: po prostu użyj multiprocessing, aby uruchomić kod intensywnie wykorzystujący pamięć w oddzielnym procesie. Nie musisz się martwić o fig.clf() lub plt.close() lub del a,b lub gc.collect(). Cała pamięć zostaje zwolniona po zakończeniu procesu.

import matplotlib 
matplotlib.use('Agg') 
import matplotlib.pyplot as plt 
import numpy as np  

import multiprocessing as mp 

def worker(): 
    N=1000000 
    a = np.arange(N) 
    b = np.random.randn(N) 

    fig = plt.figure(num=1, dpi=100, facecolor='w', edgecolor='w') 
    fig.set_size_inches(10,7) 
    ax = fig.add_subplot(111) 
    ax.plot(a, b) 

    fig.savefig('/tmp/random.png') # code gives me an error here 

if __name__=='__main__': 
    proc=mp.Process(target=worker) 
    proc.daemon=True 
    proc.start() 
    proc.join() 

Nie musisz też proc.join(). join zablokuje główny proces, dopóki nie zakończy się worker. Jeśli pominiesz join, główny proces będzie kontynuowany z procesem worker działającym w tle.

+0

Kod Zamieściłem nie powiedzie za pierwszym razem. Został stworzony w celu odtworzenia szczególnego przypadku użytkownika, który zbytnio powiększa oś y, aby uzyskać dane o wysokiej częstotliwości próbkowania. Jeśli wykres wygląda jak pranie niebieskie bez żadnego białego tła, kod kończy się niepowodzeniem. Jednak Twoje rozwiązanie wygląda na lepszy sposób zarządzania pamięcią. Jestem nowicjuszem i nie do końca rozumiem, co się dzieje z blokiem 'if __name__ == '__main __':'. Spróbuję dodać to do mojego kodu. Czy możesz wskazać mi źródło, które wyjaśnia, co się dzieje? Czy możesz zaoferować szybkie wyjaśnienie. Dzięki. – sequoia

+0

@sequoia: W takim przypadku może trzeba ograniczyć użytkownika, aby w żadnym przypadku użytkownik nie mógł wydrukować 1e6 punktów. Blok 'if __name __...' nie jest konieczny, chyba że jesteś w systemie Windows. Z przyjemnością spróbuję wyjaśnić wszelkie twoje pytania, ale myślę, że w tym przypadku wszystko jest wyjaśnione znacznie lepiej niż ja [tutaj] (http://docs.python.org/library/multiprocessing.html#the -process-class) – unutbu

+0

Dzięki, to jest pomocne łącze. Zamierzam użyć twojej implementacji. I weź swoją sugestię, aby ograniczyć zakres żądań użytkowników. – sequoia