[英]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;
隨着時間的推移,一些內存的屏幕快照會逐漸增加,您會注意到不受管理的內存正在逐漸增加:
我現在用光了所有選項。 關於嘗試的事情還有其他建議嗎?
我嘗試過的其他一些事情:
如果您想了解我的設置的其他詳細信息,請告訴我。
我在C#引擎中每次執行IronPython 2.7.5腳本時遇到內存泄漏的完全相同的問題。
在每次執行腳本后,您都應手動斷開與MarshalByRef對象的連接,否則您可能會堅持使用這些對象。 如果在MarshalByRef對象中,您已經覆蓋了InitializeLifetimeService以防止遠程處理異常,則必須手動斷開連接,如下所示:
System.Runtime.Remoting.RemotingServices.Disconnect(MarshalByRefObj obj)
希望您已經成功從引擎中刪除了Debug選項,我想知道這是否對您有用。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.