【发布时间】:2019-11-08 07:22:58
【问题描述】:
我在我的应用程序中使用了一个名为 muParserNET 的库。 muParserNET 是一个函数解析库,我的应用程序从不同的线程多次调用它。
muParserNET 由一个带有托管 C# 包装器的 C++(非托管)dll 组成。在这个包装器中,它在初始化时将指向错误处理例程的指针传递给非托管库。
即在 Parser 类中,我们有这个功能:
/// <summary>
/// Error handler. It loads the ParserError exception.
/// </summary>
private void ErrorHandler()
{
IntPtr ptrMessage = MuParserLibrary.mupGetErrorMsg(this.parserHandler);
string message = Marshal.PtrToStringAnsi(ptrMessage);
IntPtr ptrToken = MuParserLibrary.mupGetErrorToken(this.parserHandler);
string token = Marshal.PtrToStringAnsi(ptrToken);
string expr = this.Expr;
ErrorCodes code = (ErrorCodes)MuParserLibrary.mupGetErrorCode(this.parserHandler);
int pos = MuParserLibrary.mupGetErrorPos(this.parserHandler);
// lança a exceção
throw new ParserError(message, expr, token, pos, code);
}
这里是解析器对象的初始化,在托管代码中。它发生在这个函数的最后一行:
public Parser()
{
// inicializa o parser
this.parserHandler = MuParserLibrary.mupCreate(0);
// inicializa o dicionário com as variáveis
this.vars = new Dictionary<string, ParserVariable>();
// inicializa as listas de delegates
this.identFunctionsCallbacks = new List<ParserCallback>();
this.funcCallbacks = new Dictionary<string, ParserCallback>();
this.infixOprtCallbacks = new Dictionary<string, ParserCallback>();
this.postfixOprtCallbacks = new Dictionary<string, ParserCallback>();
this.oprtCallbacks = new Dictionary<string, ParserCallback>();
// inicializa o delegate de factory
this.factoryCallback = new ParserCallback(new IntFactoryFunction(this.VarFactoryCallback));
// ajusta a função de tratamento de erros
MuParserLibrary.mupSetErrorHandler(this.parserHandler, this.ErrorHandler);
}
在运行此代码时,偶尔在调用评估函数时(因此在对象初始化后的某个时间)我收到此错误:
A callback was made on a garbage collected delegate of type 'muParserNET!muParserNET.ErrorFuncType::Invoke'
ErrorFuncType 是上面使用 MuParserLibrary.mupSetErrorHandler 传递的 this.ErrorHandler 的类型。
我的理解是,由于在将指针传递给非托管代码后未使用错误处理函数,因此它会被垃圾收集。我怎样才能防止这种情况发生?
更多信息基于第一个回复: 解析器对象是在一个计算例程中创建的,该例程通常可以同时在多达 8 个单独的线程上运行。该对象是在计算例程中创建和处理的。出于这个原因,我不想将解析器对象创建为静态的,因为它会限制我在任何时候都只能有一个线程使用解析器。
【问题讨论】:
-
在某个静态字段中保留对
Parser类的引用?实际上很难告诉您最好的方法,因为我们不知道应用程序中所有对象的生命周期的上下文,但是在您的应用程序生命周期中存在的对象之一需要直接或间接引用Parser 实例(或者您需要将其放在静态字段中,但这有点全局变量) -
谢谢。上面添加了更多信息。
标签: c# garbage-collection unmanaged managed