簡體   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