2015-09-29 17 views
6

Ich habe ein Python-Skript, das viele Simulationen für verschiedene Parameter (Q, K), Plots Ergebnisse und speichert sie auf der Festplatte der Fall ist.Numpy und matplotlib Garbage Collection

Jeder Parametersatz (Q,K) erzeugt ein dreidimensionales Volumenraster mit 200x200x80 Datenpunkten, für das ca. 100 MB Daten benötigt werden. Ein Teil dieses volumetrischen Rasters wird dann Schicht für Schicht aufgetragen, wobei ~ 60 Bilder erzeugt werden.

Das Problem ist, dass Python offensichtlich nicht Speicher während dieses Prozesses freigibt. Ich bin mir nicht sicher, wo der Speicherleck ist, oder was die Regeln regeln, wie Python entscheidet, welche Objekte freigegeben werden. Ich bin auch nicht sicher, ob der Speicher in numpy Arrays oder in matplotlib Abbildung Objekte verloren ist.

  1. Gibt es eine einfache Art und Weise, die in Python-Objekte zu analysieren im Speicher fortbestehen und die automatisch freigegeben wurden?
  2. Gibt es eine Möglichkeit, Python zu zwingen, alle Arrays und Abbildung Objekte zu entziehen, die in bestimmten Schleife Zyklus oder insbesondere Funktionsaufruf erstellt wurden?

Der relevante Teil des Codes ist hier (wie auch immer, wird es nicht laufen ... der größere Teil der Code-Simulation einschließlich ctypes C++/Python-Schnittstelle weggelassen, weil es zu kompliziert ist):

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

Das Problem ist, dass Sie alle Zahlen herum und offen halten. Wenn Sie die "pyplot" State-Machine-Schnittstelle verwenden möchten, müssen Sie die Figuren jedes Mal explizit schließen. Andernfalls werden sie beibehalten, sodass sie beim Aufruf von "plt.show" angezeigt werden können. Zur schnellen Lösung rufen Sie 'plt.close()' nach 'plt.savefig' auf. –

+0

Ahoj Prokope, probieren Sie einen anderen Weg, um Matplotlib zu nutzen >>> ** ['Interaktive Anwendungen mit Matplotlib; Benjamin V. Root, (2015) '] ** – user3666197

+0

Als eine Vorspeise, kann viel Spaß beim Betrachten eines eingebetteten MVC - ** live-'matplotlib'-GUI-Beispiel >>> http://stackoverflow.com/a/25769600/3666197 ** – user3666197

Antwort

7

Versuchen Sie Ihre Figur wieder zu verwenden:

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

oder schließen Sie Ihre Figur nach dem Speichern:

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

aha, danke, es scheint, dass mit 'plt.close()' kein Speicherleck mehr vorhanden ist. Dennoch wäre es gut, eine klare Vorstellung davon zu haben, was die Regeln sind und wie man diese Lecks analysiert. –

+0

Es gibt kein Leck, wenn Sie pyplot verwenden plt.figure gibt Ihnen jedes Mal eine neue Zahl und die alte wird noch verfügbar sein, indem Sie 'plt.figure (n)' aufrufen, wobei n die Zahl der Figur ist. – tillsten