2009-11-03 29 views
8

Necesito un poco de ayuda para encontrar una solución a una pérdida de memoria que estoy teniendo. Tengo una aplicación C# (.NET v3.5) que permite a un usuario ejecutar scripts de IronPython para fines de prueba. Los scripts pueden cargar diferentes módulos de la biblioteca estándar de Python (como se incluye con los binarios de IronPython). Sin embargo, cuando se completa el script, la memoria asignada a los módulos importados no es basura. El bucle a través de varias ejecuciones de un script (hecho para pruebas de estrés) hace que el sistema se quede sin memoria durante el uso a largo plazo.Embedded IronPython pérdida de memoria

Aquí es una versión simplificada de lo que estoy haciendo.

clase de secuencias de comandos principal función:

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 ejemplo de script 'test.py' que carga el módulo random (añade ~ 1.500 KB de memoria):

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

Un mecanismo de bucle que se hacer que el sistema se quede sin memoria:

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

he añadido la sección de no optimizar la compilación basado en lo que encontré en el hilo this, pero la pérdida de memoria ocurre de cualquier manera. Agregar la llamada explícita a s.Dispose() tampoco hace ninguna diferencia (como se esperaba). Actualmente estoy usando IronPython 2.0, pero también intenté actualizar a IronPython 2.6 RC2 sin ningún éxito.

¿Cómo consigo los módulos importados en el guión IronPython incrustado sea recolectado como objetos .NET normales cuando el motor de secuencias de comandos/runtime se sale del ámbito?

Respuesta

6

usando ironpython 2.6 RC 2, y 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(); 
      } 
    } 
} 

y mi bucle es

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

el uso de la memoria aumenta a aproximadamente 70,000K, pero luego se nivela.

+0

Sí, esto funciona bien con IronPython 2.6 RC2. Pero no funcionó con IronPython 2.0.1. Desafortunadamente, 2.6 RC2 tiene problemas para importar variables al espacio de nombres global. Voy a probar 2.0.3 y publicar resultados. Gracias por la ayuda hasta ahora :) – cgyDeveloper

+0

2.0.3 tampoco es bueno. – cgyDeveloper

4

Ha intentado ejecutar el pitón de Hierro en su propio dominio de aplicación? Python.CreateEngine le permite pasarle un AppDomain, que luego puede descargarse cuando se complete el script.

O, basado en this discusión, utilice la opción LightweightScopes, al igual que

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

simple y eficaz como una solución, había pasado por alto esto. Al forzar que el AppDomain se descargue, la pérdida de memoria se controla (aunque mi huella global ha aumentado al usar un Dominio de aplicación). – cgyDeveloper

+0

Buena respuesta, pero voy a mantener esta abierto para un día o dos para ver si alguien tiene una solución que podría solucionar el problema, ya que esto es realmente sólo una solución temporal. – cgyDeveloper

+0

LightweightScopes no funciona. Según la discusión a la que se vinculó, probablemente solo resuelva el problema de volver a cargar un módulo dentro de un script donde ya está cargado. Mi problema es la recolección de basura que no ocurre cuando se completa el script. No me sorprendería, sin embargo, si ambos problemas tienen la misma causa raíz en el DLR. – cgyDeveloper