访问变量解决方案值时出现 AccessViolationException

AccessViolationException when accessing variable solution value

我们一直在利用 OR 工具解决实时 .NET 应用程序中的线性优化问题。也就是说,随着时间的推移使用不同的输入定期求解线性优化。

最近我们 运行 遇到了一个我们以前从未见过的问题,而 运行 我们的应用程序在服务器上长时间运行,其中看似 运行dom 试图解决导致 AccessViolationExceptions 的优化。具体来说,

Framework Version: v4.0.30319 Description: The process was terminated due to an unhandled exception. Exception Info: System.AccessViolationException at Google.OrTools.LinearSolver.operations_research_linear_solverPINVOKE.Variable_SolutionValue(System.Runtime.InteropServices.HandleRef) ...

我试图更具体地找出管道中发生这种情况的位置,但考虑到那里的输出,我相信这是一个我们试图在之后从求解器中检索单个变量解决方案值的部分求解优化。

我们对相当数量的变量使用了各种各样的约束。

有人以前看过这个吗?

Reference github issue link

经过一些测试后,我们发现垃圾收集器似乎正在收集我们在 P/Invoke 期间使用的一些变量,根据 this

不幸的是,这似乎是 SWIG 创建其 .NET 包装器及其 IDisposable 实现方式的副作用,使用 HandleRefs 而不是 SafeHandles 之类的东西,'handle' 这是根据文档:

Platform invoke operations automatically increment the reference count of handles encapsulated by a SafeHandle and decrement them upon completion. This ensures that the handle will not be recycled or closed unexpectedly.

更多信息here

不想参与创建我们自己的 SWIG 类型映射或编译新版本的 SWIG 的业务,.NET 提供了一种保留对象 'alive' 关于垃圾收集器的方法。也就是说,在 end 处调用 GC.KeepAlive 我们将通过 P/Invoke (在我们的例子中是求解器和我们的变量)访问值的所有对象优化过程的一部分,防止垃圾收集器认为它们是可收集的,直到 KeepAlive 方法的范围结束而没有副作用(根据他们的文档)。

初步测试表明这是可行的,但考虑到它之前已经间歇性地发生过,我们将继续关注这种情况的发生。

展望未来,我认为要么让 SWIG 请求使用 SafeHandles 可能是最好的主意(已经讨论过 before 并且仍然是一个悬而未决的问题)或者更改类型映射直接使用 SafeHandles 可能是最好的选择。我可能会尝试自己研究后面的选项,但因为这个修复程序最终只向我们的代码库添加了 3 行代码(加上大量注释),看起来像是一个完整的修复程序,所以它对我来说将是低优先级的。也就是说,对于即将发布的版本来说,对此的修复会很好。