У меня есть сценарий, написанный на python. Я его цитонизирую и подключаю как C ++ модуль. Исходя из этого, я создаю dll и подключаю его к проекту в c #, где вызов библиотеки должен go через несколько раз.
Проблема возникает именно при повторном запуске библиотеки, потому что при первой обработке скрипта ОЗУ не очищается, что не позволяет перезапустить его. Python состоит из модулей, которые занимают много памяти, поэтому одноразовое использование библиотеки занимает 160 МБ ОЗУ. Я пытался использовать Py_Finalize (), но, насколько я понимаю, он удалил для меня только динамические c разделы (~ 86 МБ), поэтому повторная инициализация оказалась ошибкой. Если вы не используете Py_Finalize (), то каждый перезапуск будет занимать + 80-90 МБ памяти, что после повторных запусков становится очень большой проблемой.
Библиотека C ++: метод запуска python
void MLWrapper::outputInfo(char * curDirPath) {
auto err = PyImport_AppendInittab("runML", PyInit_runML);
wchar_t* szName = GetWC(curDirPath);
Py_SetPythonHome(szName);
Py_Initialize();
auto module = PyImport_ImportModule("runML");
mlDataG.predictionResult = runTab(&mlDataG);
Py_Finalize();}
C#: класс для работы с dll
public class ExternalHelpers : IDisposable
{
private IntPtr _libraryHandle;
private OutputInfoDelegate _outputInfo;
private delegate void OutputInfoDelegate([MarshalAs(UnmanagedType.LPStr)]string dirPath);
public ExternalHelpers()
{
_libraryHandle = UnsafeMethods.LoadLibrary("MLWrapper.dll");
if (_libraryHandle == IntPtr.Zero)
{
Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
}
_outputInfo = LoadExternalFunction<OutputInfoDelegate>(@"?outputInfo@MLWrapper@@YAXPEAD@Z") as OutputInfoDelegate;
}
public void OutputInfo(string path)
{
_outputInfo(path);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
~ExternalHelpers()
{
Dispose(false);
}
private Delegate LoadExternalFunction<Delegate>(string functionName)
where Delegate : class
{
IntPtr functionPointer =
UnsafeMethods.GetProcAddress(_libraryHandle, functionName);
if (functionPointer == IntPtr.Zero)
Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
// Marshal to requested delegate
return Marshal.GetDelegateForFunctionPointer(functionPointer, typeof(Delegate)) as Delegate;
}
private void Dispose(bool disposing)
{
if (disposing)
{
_outputInfo = null;
}
if (_libraryHandle != IntPtr.Zero)
{
while (UnsafeMethods.FreeLibrary(_libraryHandle) == true)
{
continue;
}
//if (!UnsafeMethods.FreeLibrary(_libraryHandle))
// Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
_libraryHandle = IntPtr.Zero;
}
}
}
C#: вызов метода
using (ExternalHelpers e = new ExternalHelpers())
{
...
e.OutputInfo(@"C:\Users\user\source\repos\Project\bin\x64\Debug");...}
Как я могу решить эту проблему?
У меня также была идея динамического подключения библиотеки. Таким образом, я смогу полностью закрыть библиотеку, и память должна быть освобождена, но когда вы очищаете память модуля, библиотека закрывается с кодом выхода: 1, и основное приложение заканчивается.
Возможно, я забыл чтобы описать некоторые другие детали, поэтому исправьте меня в комментариях, если требуется дополнительная информация