嵌入式IronPython内存泄漏

时间:2009-11-03 00:31:36

标签: .net memory-leaks ironpython

我需要一些帮助来找到我遇到的内存泄漏的解决方案。我有一个C#应用程序(.NET v3.5),允许用户运行IronPython脚本进行测试。脚本可以加载Python标准库中的不同模块(包含在IronPython二进制文件中)。但是,当脚本完成时,分配给导入模块的内存不会被垃圾回收。循环使用一个脚本的多次运行(完成压力测试)会导致系统在长期使用期间耗尽内存。

以下是我正在做的简化版本。

脚本类主要功能:

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

加载随机模块的示例'test.py'脚本(添加~1500 KB的内存):

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

一种循环机制,会导致系统内存不足:

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

我添加了基于我在this线程中找到的内容不优化编译的部分,但内存泄漏发生在任何一种方式。将显式调用添加到s.Dispose()也没有任何区别(如预期的那样)。我目前正在使用IronPython 2.0,但我也尝试过升级到IronPython 2.6 RC2而没有任何成功。

当脚本引擎/运行时超出范围时,如何让嵌入式IronPython脚本中导入的模块像普通的.NET对象一样被垃圾收集?

3 个答案:

答案 0 :(得分:6)

使用Iron Python 2.6 RC 2和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();
            }
    }
}

我的循环是

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

内存使用量增加到大约70,000K,但随后关闭。

答案 1 :(得分:4)

您是否尝试在自己的appDomain中运行Iron python? Python.CreateEngine允许您将AppDomain传递给它,然后在脚本完成时卸载它。

或者,根据this讨论,使用LightweightScopes选项,如此

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

答案 2 :(得分:0)

另一个答案对我帮助不大,所以我发布了我的解决方法。我所做的是在我的 while 循环之外设置脚本范围和引擎。我的内存泄漏以前增长得非常快,但通过这个修复,我能够阻止它。

我留在循环中的唯一内容是来自我的 Python 脚本的实际调用。这是我脚本的开始。

var engine = Python.CreateEngine();
        scope = engine.CreateScope();
        ICollection<string> paths = engine.GetSearchPaths();
        paths.Add(@"C:\Python27");
        paths.Add(@"C:\Python27\Lib");
        paths.Add(@"C:\Python27\Lib\site-packages");
        engine.SetSearchPaths(paths);
        paths = engine.GetSearchPaths();
        engine.ExecuteFile(path, scope);


        while (!stoppingToken.IsCancellationRequested)
        {
           Run();
        }

我还在我的类中声明了一个私有的 ScriptScrope,这样我就可以从其他方法调用作用域而无需传递作用域。

public class Worker : BackgroundService
{
    private readonly ILogger<Worker> _logger;
    private ScriptScope scope;

然后在我刚刚添加的“运行”方法中:

var result= scope.GetVariable("MyPythonMethod");

现在我的内存使用量保持在 130 MB 而不是 1GB+。