【发布时间】:2020-05-13 15:00:16
【问题描述】:
我有一个用 python 编写的脚本。我对它进行 cytonize 并将其作为 C++ 模块插入。由此,我创建了 dll 并将其连接到 c# 中的项目,其中库调用必须经过多次。
问题正是由于库的重复启动而出现的,因为第一次处理脚本时,RAM 没有被清除,这会阻止它重新启动。 Python 由占用大量内存的模块组成,因此单次使用该库需要 160MB 的 RAM。 我尝试使用 Py_Finalize(),但据我了解,他只为我删除了动态部分(~86MB),所以重新初始化结果是一个错误。如果不使用Py_Finalize(),那么每次重启都会占用+80-90MB的内存,重复启动后就会成为一个很大的问题。
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 并且主应用程序结束。
也许我忘了描述一些其他细节,如果需要更多信息,请在 cmets 中纠正我
【问题讨论】:
-
您编写了一个在 c++ 中运行的 python 程序,您从 c# 调用?是否有机会将其完全转换为一种语言?
-
为什么不仅在 Python 解释器尚未初始化时才初始化,即在使用
Py_IsInitialized()查询状态并仅在程序关闭时才完成?一些扩展(我认为 numpy 是(或至少是)其中之一)在同一进程中多次初始化/完成时存在问题(不确定内存泄漏是可能发生的最坏情况)。
标签: c# python c++ memory-leaks cython