2009-11-03 17 views
8

Ho bisogno di aiuto per trovare una soluzione a una perdita di memoria che sto avendo. Ho un'applicazione C# (.NET v3.5) che consente a un utente di eseguire script IronPython a scopo di test. Gli script possono caricare diversi moduli dalla libreria standard Python (come incluso con i binari di IronPython). Tuttavia, al termine dello script, la memoria allocata ai moduli importati non viene raccolta. Il ciclo di più esecuzioni di uno script (eseguito per test di stress) causa l'esaurimento della memoria del sistema durante l'utilizzo a lungo termine.Perdita di memoria IronPython incorporata

Ecco una versione semplificata di ciò che sto facendo.

classe Script funzione principale:

public void Run() 
{ 
    // set up iron python runtime engine 
    this.engine = Python.CreateEngine(pyOpts); 
    this.runtime = this.engine.Runtime; 
    this.scope = this.engine.CreateScope(); 

    // compile from file 
    PythonCompilerOptions pco = (PythonCompilerOptions)this.engine.GetCompilerOptions(); 
    pco.Module &= ~ModuleOptions.Optimized; 
    this.script = this.engine.CreateScriptSourceFromFile(this.path).Compile(pco); 

    // run script 
    this.script.Execute(this.scope); 

    // shutdown runtime (run atexit functions that exist) 
    this.runtime.Shutdown(); 
} 

Un 'test.py' script di esempio che carica il modulo random (aggiunge ~ 1500 KB di memoria):

import random 
print "Random number: %i" % random.randint(1,10) 

Un meccanismo di loop che verrà causa di esaurimento della memoria del sistema:

while(1) 
{ 
    Script s = new Script("test.py"); 
    s.Run(); 
    s.Dispose(); 
} 

Ho aggiunto la sezione per non ottimizzare la compilazione in base a ciò che ho trovato nel thread this, ma la perdita di memoria si verifica in entrambi i casi. Anche l'aggiunta della chiamata esplicita a s.Dispose() non fa differenza (come previsto). Attualmente sto usando IronPython 2.0, ma ho anche provato ad aggiornare IronPython 2.6 RC2 senza alcun successo.

Come si ottengono i moduli importati nello script IronPython incorporato da raccogliere come normali oggetti .NET quando il motore di scripting/runtime esce dall'ambito?

risposta

6

utilizzando ironpython 2.6 RC 2 e C# 3,5

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using Microsoft.Scripting.Hosting; 
using IronPython.Hosting; 

namespace IPmemTest { 
    class IPy { 
     private string script = "import random; random.randint(1,10)"; 

     public IPy() { 
     } 

     public void run() { 
      //set up script environment 
      Dictionary<String, Object> options = new Dictionary<string, object>(); 
      options["LightweightScopes"] = true; 
      ScriptEngine engine = Python.CreateEngine(options); 
      ScriptRuntime runtime = engine.Runtime; 
      ScriptScope scope = runtime.CreateScope(); 
      var source = engine.CreateScriptSourceFromString(this.script); 
      var comped = source.Compile(); 
      comped.Execute(scope); 
      runtime.Shutdown(); 
      } 
    } 
} 

e il mio ciclo è

class Program { 
     static void Main(string[] args) { 
      while (true) { 
       var ipy = new IPy(); 
       ipy.run(); 
      } 
     } 
    } 

l'utilizzo della memoria aumenta fino a circa 70.000 K, ma poi si livella.

+0

Sì, funziona perfettamente con IronPython 2.6 RC2. Ma non ha funzionato con IronPython 2.0.1. Sfortunatamente, 2.6 RC2 sta incontrando problemi nell'importazione di variabili nello spazio dei nomi globale. Ho intenzione di provare 2.0.3 e postare risultati. Grazie per l'aiuto finora :) – cgyDeveloper

+0

2.0.3 non va bene, neanche. – cgyDeveloper

4

Hai provato a eseguire il python Iron nella propria appDomain? Python.CreateEngine ti consente di passargli un AppDomain, che può essere scaricato quando lo script termina.

Oppure, sulla base di this discussione, utilizzare l'opzione LightweightScopes, in questo modo

Dictionary<String, Object> options = new Dictionary<string, object>(); 
options["LightweightScopes"] = true; 
ScriptEngine engine = Python.CreateEngine(options); 
ScriptRuntime runtime = engine.Runtime; 
+0

Semplice ed efficace come soluzione, l'ho trascurato. Forzando l'AppDomain per scaricare, la perdita di memoria è controllata (anche se il mio ingombro complessivo è aumentato utilizzando un AppDomain). – cgyDeveloper

+0

Buona risposta, ma terrò questo aperto per un giorno o due per vedere se qualcuno ha una soluzione che potrebbe risolvere il problema, in quanto questa è solo una soluzione. – cgyDeveloper

+0

LightweightScopes non funziona. In base alla discussione a cui ti sei collegato, probabilmente risolverà solo il problema di ricaricare un modulo all'interno di uno script in cui è già stato caricato. Il mio problema è la garbage collection che non si verifica quando lo script è completato. Non sarei sorpreso, tuttavia, se entrambi i problemi hanno la stessa causa alla radice nel DLR. – cgyDeveloper