2015-09-29 14 views
6

Mam skrypt Pythona, który robi wiele symulacji dla różnych parametrów (Q, K), działki wyników i zapisuje go na dysku.Numpy i matplotlib garbage collection

Każdy zestaw parametrów (Q,K) generuje trójwymiarową siatkę wolumetryczną danych o punktach danych 200x200x80, która wymaga ~ 100 MB danych. Część tej wolumetrycznej siatki jest następnie spiętrzana, warstwa po warstwie, co daje ~ 60 obrazów.

Problem polega na tym, że python oczywiście nie zwalnia pamięci podczas tego procesu. Nie jestem pewien, gdzie jest wyciek pamięci lub jakie reguły decydują o tym, w jaki sposób python decyduje, które obiekty są deallokowane. Nie jestem również pewien, czy pamięć zostanie utracona w tablicach numpy lub obiektach figur matplotlib.

  1. Czy istnieje prosty sposób analizować który obiektów w python utrzymują się w pamięci i które zostały automatycznie zwalniane?
  2. Czy istnieje sposób zmuszenia Pythona do zwolnienia wszystkich tablic i obiektów figur, które zostały utworzone w określonym cyklu pętli lub w konkretnym wywołaniu funkcji?

Odpowiedni fragment kodu jest tutaj (jednak nie będzie działać ... im większa część kodu symulacyjnego tym ctypes C++/interfejs Pythona zostanie pominięty, ponieważ jest to zbyt skomplikowane):

import numpy as np 
import matplotlib.pyplot as plt 
import ProbeParticle as PP # this is my C++/Python simulation library, take it as blackbox 

def relaxedScan3D(xTips, yTips, zTips): 
    ntips = len(zTips); 
    print " zTips : ",zTips 
    rTips = np.zeros((ntips,3)) # is this array deallocated when exiting the function? 
    rs = np.zeros((ntips,3)) # and this? 
    fs = np.zeros((ntips,3)) # and this? 
    rTips[:,0] = 1.0 
    rTips[:,1] = 1.0 
    rTips[:,2] = zTips 
    fzs = np.zeros((len(zTips), len(yTips), len(xTips))); # and this? 
    for ix,x in enumerate(xTips ): 
     print "relax ix:", ix 
     rTips[:,0] = x 
     for iy,y in enumerate(yTips ): 
      rTips[:,1] = y 
      itrav = PP.relaxTipStroke(rTips, rs, fs)/float(len(zTips)) 
      fzs[:,iy,ix] = fs[:,2].copy() 
    return fzs 


def plotImages(prefix, F, slices): 
    for ii,i in enumerate(slices): 
     print " plotting ", i 
     plt.figure(figsize=(10,10)) # Is this figure deallocated when exiting the function ? 
     plt.imshow(F[i], origin='image', interpolation=PP.params['imageInterpolation'], cmap=PP.params['colorscale'], extent=extent) 
     z = zTips[i] - PP.params['moleculeShift' ][2] 
     plt.colorbar(); 
     plt.xlabel(r' Tip_x $\AA$') 
     plt.ylabel(r' Tip_y $\AA$') 
     plt.title(r"Tip_z = %2.2f $\AA$" %z ) 
     plt.savefig(prefix+'_%3.3i.png' %i, bbox_inches='tight') 

Ks = [ 0.125, 0.25, 0.5, 1.0 ] 
Qs = [ -0.4, -0.3, -0.2, -0.1, 0.0, +0.1, +0.2, +0.3, +0.4 ] 

for iq,Q in enumerate(Qs): 
    FF = FFLJ + FFel * Q 
    PP.setFF_Pointer(FF) 
    for ik,K in enumerate(Ks): 
     dirname = "Q%1.2fK%1.2f" %(Q,K) 
     os.makedirs(dirname) 
     PP.setTip(kSpring = np.array((K,K,0.0))/-PP.eVA_Nm) 
     fzs = relaxedScan3D(xTips, yTips, zTips) # is memory of "fzs" recycled or does it consume more memory each cycle of the loop ? 
     PP.saveXSF(dirname+'/OutFz.xsf', headScan, lvecScan, fzs) 
     dfs = PP.Fz2df(fzs, dz = dz, k0 = PP.params['kCantilever'], f0=PP.params['f0Cantilever'], n=int(PP.params['Amplitude']/dz)) # is memory of "dfs" recycled? 
     plotImages(dirname+"/df", dfs, slices = range(0, len(dfs))) 
+3

Problem polega na tym, że wszystkie liczby są otwarte i otwarte. Jeśli zamierzasz używać interfejsu stanu maszyny "pyplot", musisz za każdym razem wyraźnie zamykać wartości. W przeciwnym razie będą one przechowywane tak, aby mogły być wyświetlane, gdy wywołasz 'plt.show'. Jako szybką naprawę wywołaj 'plt.close()' po 'plt.savefig'. –

+0

Ahoj Prokope, spróbuj zasmakować w inny sposób, jak wykorzystać matplotlib >>> ** ["Aplikacje interaktywne przy użyciu Matplotlib; Benjamin V. Root, (2015) '] ** – user3666197

+0

Jako przekąska, możesz cieszyć się oglądaniem wbudowanego MVC - ** live-' matplotlib'-GUI sample >>> http://stackoverflow.com/a/25769600/3666197 ** – user3666197

Odpowiedz

7

Spróbuj ponownie wykorzystać swoją postać:

plt.figure(0, figsize=(10, 10)) 
plt.clf() #clears figure 

lub zamknąć figurę po zapisaniu:

... 
plt.savefig(...) 
plt.close() 
+1

aha, dziękuję, wydaje się, że z 'plt.close()' nie ma już przecieku pamięci. Wciąż dobrze byłoby mieć jasne pojęcie, jakie są zasady i jak analizować te wycieki. –

+0

Nie ma wycieku, jeśli użyjesz pyplot, plt.figure da ci nową figurę za każdym razem, a stara będzie nadal dostępna przez wywołanie 'plt.figure (n)' gdzie n jest numerem figury. – tillsten

Powiązane problemy