繁体   English   中英

IronPython 2.7.7 C#集成内存泄漏

[英]IronPython 2.7.7 C# Integration Memory Leak

我正在整合IronPython脚本以在C#引擎下运行。 C#引擎构建“ ScriptValue”对象的字典,并将其传递到IronPython脚本,然后该IronPython脚本使用这些对象进行计算。 “ ScriptValue”对象位于单独的类库中,并实现“ MarshalByRefObject”,并且是一个简单的.net对象(仅存储double和bool值)。 脚本运行频繁发生。

第一次尝试:我实例化了IronPython引擎并运行了脚本。 随着运行的进行,我可以看到内存使用量正在快速增加。 最终,经过一天的运行或运行,应用程序因内存不足异常而崩溃。 我尝试使IronPythonEngine的一个实例保持活动状态,并在每次运行时都重新启动一个新实例。 我也尝试关闭IronPython引擎,但是内存会持续增加。

第二次尝试:经过大量研究,提出了一些建议,尝试在单独的AppDomain中运行引擎,并在完成脚本运行后卸载AppDomain。 然后,我实现了这一点并创建了一个新的AppDomain,并在运行完成后将其卸载。 这似乎在一定程度上有所帮助,但是内存泄漏仍然存在,尽管它以较慢的速度上升。

我做了各种内存分析,似乎IronPython或DLR中的某个地方未托管的内存没有被释放,并且随着时间的流逝而逐渐增加。 随着AppDomain的卸载,托管内存似乎正在清除。

C#引擎本身非常复杂,并且与MS SQL,IronPython,Data Historian和资产数据库进行交互。 我不再赘述,因为我已经能够通过将所有其他组件都带到一个简单的Windows Forms应用程序中来重新创建该问题。

我目前在计时器下运行的代码是:

private void RunEngine()
{

    ScriptEngine pythonEngine = null;
    AppDomain sandbox = null;
    ScriptSource source = null;
    ScriptScope scope = null;
    dynamic subClass = null;
    ObjectOperations ops = null;
    dynamic instance = null;
    dynamic result = null;

    Dictionary<string, ScriptValue> scriptInputValues = GetIronPythonScriptInputAttributeValues();
    Dictionary<string, ScriptValue> scriptOutputValues = GetIronPythonScriptOutputAttributes();

    // Setup PythonEngine options
    Dictionary<string, object> options = new Dictionary<string, object>();
    //options["Debug"] = ScriptingRuntimeHelpers.True;
    options["ExceptionDetail"] = ScriptingRuntimeHelpers.True;
    options["ShowClrExceptions"] = ScriptingRuntimeHelpers.True;

    // Create a sandbox to run the IronPython scripts in
    sandbox = AppDomain.CreateDomain("IronPythonSandbox",
                                                      AppDomain.CurrentDomain.Evidence,
                                                    new AppDomainSetup() { ApplicationBase = AppDomain.CurrentDomain.BaseDirectory, ApplicationName = "IronPythonSandbox" },
                                                    new PermissionSet(PermissionState.Unrestricted));

    // Create the python engine
    pythonEngine = Python.CreateEngine(sandbox, options);
    source = pythonEngine.CreateScriptSourceFromFile(@"\\server2\Projects\Customer\Development\Scripts\calculation.py");
    var compiled = source.Compile();
    scope = pythonEngine.CreateScope();
    //source.Execute(scope);
    compiled.Execute(scope);
    subClass = scope.GetVariableHandle("Calculate");
    ops = pythonEngine.Operations;
    instance = ops.Invoke(subClass, scriptInputValues, scriptOutputValues);
    result = instance.Unwrap();

    if (scriptInputValues?.Count > 0) { scriptInputValues.Clear(); scriptInputValues = null; }
    if (scriptOutputValues?.Count > 0) { scriptOutputValues.Clear(); scriptOutputValues = null; }

    result = null;
    instance = null;
    ops = null;
    subClass = null;
    scope = null;
    source = null;
    pythonEngine?.Runtime?.Shutdown();
    pythonEngine = null;
    if (sandbox != null) { AppDomain.Unload(sandbox); }
    sandbox = null;

}

我现在将脚本精简了一下,以测试内存问题,它就是这样,并且不进行任何实际的计算。

import clr
import sys

# Import integration library to allow for access to the required .Net object types
sys.path.append(r"C:\Program Files\Company\RTCM Worker") # Include the path to the .Net Library
clr.AddReference('RTCM.Worker.IPy.Integration.Library.dll')
import RTCM.Worker.IPy.Integration.Library

import System
from System.Collections.Generic import Dictionary

sys.path.append(r"\\server2\Projects\Customer\Development\Scripts") # Include the path to the module
from constants import *
from sharedfunctions import *

import math


def Calculate(scriptInputValues, scriptOutputValues):

    returnValue = True

    try:

        # Parameter validations

        if returnValue: # Only proceed with the calculation if all inputs are valid

            ## Script logging related objects
            #ENABLE_SCRIPTLOGGING = scriptOutputValues[C_EnableScriptLogging].Value
            #SCRIPT_LOG = scriptOutputValues[C_ScriptLog].Value

            # Get all the required input parameter values
            AMB_TEMP = scriptInputValues[C_AmbientTemperature].Value
            GND_AIR = scriptInputValues[C_GroundAir].Value
            MAX_DESIGN_TEMP = scriptInputValues[C_MaximumDesignTemperature].Value
            g = scriptInputValues[C_RatingCalculationConstants_g].Value
            CONDUCTOR_DIA = scriptInputValues[C_ConductorDIA].Value
            WIND_SPEED = scriptInputValues[C_WindSpeed].Value # From lookup table and no conversion needed as this is in m/s
            DEFAULT_WIND_ANGLE = scriptInputValues[C_WindBearing].Value
            SIGMA = scriptInputValues[C_Rating_Calculation_Constants_SIGMA].Value
            CONDUCTOR_EMISSIVITY = scriptInputValues[C_ConductorEmissivity].Value
            SOLAR_ABSORPTION = scriptInputValues[C_SolarAbsorption].Value
            SOLAR_DIRECT = scriptInputValues[C_SolarDirect].Value
            GROUND_REFLECTIVITY = scriptInputValues[C_GroundReflectivity].Value
            SOLAR_DIFFUSE = scriptInputValues[C_SolarDiffuse].Value
            CONDUCTOR_SKIN_EFFECT = scriptInputValues[C_ConductorSkinEffect].Value
            CONDUCTOR_MAG_EFFECT = scriptInputValues[C_ConductorMAGEffect].Value
            CONDUCTOR_DC_RESISTANCE = scriptInputValues[C_ConductorDCResistance].Value
            CONDUCTOR_ALPHA = scriptInputValues[C_ConductorAlpha].Value


            # Destroy all referenced objects
            del AMB_TEMP
            del GND_AIR
            del MAX_DESIGN_TEMP
            del g
            del CONDUCTOR_DIA
            del WIND_SPEED
            del DEFAULT_WIND_ANGLE
            del SIGMA
            del CONDUCTOR_EMISSIVITY
            del SOLAR_ABSORPTION
            del SOLAR_DIRECT
            del GROUND_REFLECTIVITY
            del SOLAR_DIFFUSE
            del CONDUCTOR_SKIN_EFFECT
            del CONDUCTOR_MAG_EFFECT
            del CONDUCTOR_DC_RESISTANCE
            del CONDUCTOR_ALPHA
            del scriptInputValues
            del scriptOutputValues

            returnValue = True

    except System.Exception as ex:
        returnValue = False

    return returnValue;

随着时间的推移,一些内存的屏幕快照会逐渐增加,您会注意到不受管理的内存正在逐渐增加:

开始运行

一段时间之后

一段时间之后

我现在用光了所有选项。 关于尝试的事情还有其他建议吗?

我尝试过的其他一些事情:

  1. 将LightweightScopes设置为true并没有帮助。
  2. 使用del关键字删除IronPython脚本中引用的对象,这没有帮助。

如果您想了解我的设置的其他详细信息,请告诉我。

我在C#引擎中每次执行IronPython 2.7.5脚本时遇到内存泄漏的完全相同的问题。

在每次执行脚本后,您都应手动断开与MarshalByRef对象的连接,否则您可能会坚持使用这些对象。 如果在MarshalByRef对象中,您已经覆盖了InitializeLifetimeService以防止远程处理异常,则必须手动断开连接,如下所示:

System.Runtime.Remoting.RemotingServices.Disconnect(MarshalByRefObj obj)

希望您已经成功从引擎中删除了Debug选项,我想知道这是否对您有用。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM