2009-11-03 23 views
8

Potrzebuję pomocy w znalezieniu rozwiązania problemu wycieku pamięci, który mam. Mam aplikację C# (.NET v3.5), która pozwala użytkownikowi na uruchamianie skryptów IronPython w celach testowych. Skrypty mogą ładować różne moduły ze standardowej biblioteki Python (jak dołączono do plików binarnych IronPython). Jednak po zakończeniu skryptu pamięć przydzielona do zaimportowanych modułów nie jest zbierana. Zapętlanie wielu przebiegów jednego skryptu (wykonywane w celu testowania warunków skrajnych) powoduje, że system wyczerpuje pamięć podczas długotrwałego użytkowania.Osadzony wyciek pamięci IronPythona

Oto uproszczona wersja tego, co robię.

klasa Script Główną funkcją:

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(); 
} 

Przykładem 'test.py' skrypt, który ładuje moduł losowego (dodaje ~ 1500 KB pamięci):

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

Mechanizm pętli, które będą bo w systemie zabrakło pamięci:

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

Dodałem sekcję, aby nie optymalizować kompilacji na podstawie tego, co znalazłem w wątku this, ale wyciek pamięci występuje w dowolny sposób. Dodanie jawnego połączenia do s.Dispose() również nie robi różnicy (zgodnie z oczekiwaniami). Obecnie korzystam z IronPython 2.0, ale próbowałem również przejść na IronPython 2.6 RC2 bez żadnego sukcesu.

W jaki sposób uzyskać, że zaimportowane moduły we wbudowanym skrypcie IronPython będą zbierane w postaci normalnych obiektów .NET, gdy silnik skryptowy/środowisko wykonawcze wykracza poza zakres?

Odpowiedz

6

użyciu ironpython 2.6 RC 2 i 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(); 
      } 
    } 
} 

i moja pętla jest

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

zużycie pamięci wzrasta do około 70 000 K, ale następnie zmniejsza się.

+0

Tak, to działa dobrze z IronPython 2.6 RC2. Ale nie działało to z IronPythonem 2.0.1. Niestety, 2.6 RC2 ma problem z zaimportowaniem zmiennych do globalnej przestrzeni nazw. Spróbuję wypróbować wersję 2.0.3 i opublikować wyniki. Dzięki za pomoc do tej pory :) – cgyDeveloper

+0

2.0.3 też nie jest dobry. – cgyDeveloper

4

Czy próbowałeś uruchomić Żelazny Python w swoim własnym appDomain? Python.CreateEngine pozwala przekazać mu AppDomain, który można następnie rozładować po zakończeniu skryptu.

Albo, na podstawie this dyskusji, użyj opcji LightweightScopes, tak jak

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

Prosty i skuteczny sposób obejścia tego problemu, przeoczyłem to. Wymuszenie wyładowania elementu AppDomain powoduje przeciek pamięci (mimo że mój ogólny zasięg wzrósł za pomocą AppDomain). – cgyDeveloper

+0

Dobra odpowiedź, ale zamierzam zachować to otwarte przez dzień lub dwa, aby sprawdzić, czy ktoś ma rozwiązanie, które może rozwiązać problem, ponieważ jest to tylko obejście problemu. – cgyDeveloper

+0

LightweightScopes nie działa. W oparciu o dyskusję, z którą się łączyłeś, prawdopodobnie rozwiązuje tylko problem przeładowania modułu w skrypcie, w którym jest już załadowany. Moim problemem jest odśmiecanie, które nie występuje, gdy skrypt jest ukończony. Nie zdziwiłbym się jednak, gdyby oba problemy miały tę samą podstawową przyczynę w DLR. – cgyDeveloper