2009-11-03 7 views
8

J'ai besoin d'aide pour trouver une solution à une fuite de mémoire que j'ai. J'ai une application C# (.NET v3.5) qui permet à un utilisateur d'exécuter des scripts IronPython à des fins de test. Les scripts peuvent charger différents modules à partir de la bibliothèque standard Python (comme inclus avec les binaires IronPython). Cependant, lorsque le script est terminé, la mémoire allouée aux modules importés n'est pas récupérée. Le bouclage à travers plusieurs exécutions d'un script (effectué pour un test de stress) entraîne l'épuisement du système en cas d'utilisation à long terme.Fuite de mémoire IronPython intégrée

Voici une version simplifiée de ce que je fais.

fonction de classe Script 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 exemple 'test.py' script qui charge le module aléatoire (ajoute ~ 1500 Ko de mémoire):

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

Un mécanisme en boucle qui sera provoque l'épuisement de la mémoire du système:

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

J'ai ajouté la section pour optimiser la compilation basé sur ce que j'ai trouvé dans this thread, mais la fuite de mémoire se produit de toute façon. L'ajout de l'appel explicite à s.Dispose() ne fait également aucune différence (comme prévu). J'utilise actuellement IronPython 2.0, mais j'ai également essayé de mettre à niveau vers IronPython 2.6 RC2 sans aucun succès. Comment faire en sorte que les modules importés dans le script IronPython incorporé soient récupérés comme des objets .NET normaux lorsque le moteur de script/l'environnement d'exécution sortent de la portée?

Répondre

6

à l'aide de fer Python 2.6 RC 2 et 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(); 
      } 
    } 
} 

et ma boucle est

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

l'utilisation de la mémoire augmente à environ 70 000 K, mais se stabilise ensuite.

+0

Oui, cela fonctionne très bien avec IronPython 2.6 RC2. Mais cela n'a pas fonctionné avec IronPython 2.0.1. Malheureusement, 2.6 RC2 rencontre des problèmes pour importer des variables dans l'espace de noms global. Je vais essayer 2.0.3 et afficher les résultats. Merci pour l'aide jusqu'à présent :) – cgyDeveloper

+0

2.0.3 n'est pas bon non plus. – cgyDeveloper

4

Avez-vous essayé d'exécuter Iron python dans son propre appDomain? Python.CreateEngine vous permet de lui passer un AppDomain, qui peut ensuite être déchargé lorsque le script se termine.

Ou, sur la base this discussion, utilisez l'option LightweightScopes, comme si

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

Simple et efficace comme une solution de contournement, j'avais négligé cela. En forçant AppDomain à décharger, la fuite de mémoire est contrôlée (bien que mon empreinte globale ait augmenté en utilisant un AppDomain). – cgyDeveloper

+0

Bonne réponse, mais je vais garder cela ouvert pendant un jour ou deux pour voir si quelqu'un a une solution qui pourrait résoudre le problème, car c'est juste une solution de contournement. – cgyDeveloper

+0

LightweightScopes ne fonctionne pas. En fonction de la discussion à laquelle vous avez lié, cela résout probablement le problème du rechargement d'un module dans un script où il est déjà chargé. Mon problème est le garbage collection qui ne se produit pas lorsque le script est terminé. Je ne serais pas surpris, cependant, si les deux problèmes ont la même cause dans le DLR. – cgyDeveloper