我们一直在使用OR工具来解决实时.NET应用程序中的线性优化问题。也就是说,随着时间的推移,使用不同的输入定期解决线性优化问题。
最近我们遇到了一个我们在服务器上长时间运行应用程序时看不到的问题,其中看似随机尝试解决优化问题导致了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)
...
我试图更具体地找出管道中发生这种情况的地方,但考虑到输出,我相信这是我们试图从解算器中检索出单个变量解决方案值的部分。解决优化问题。
我们对大小合适的变量使用了各种各样的约束。
有没有人见过这个?
答案 0 :(得分:0)
经过一些测试后,我们发现似乎发生的事情是垃圾收集器正在收集我们在P / Invoke期间使用的一些变量,按照this。
不幸的是,这似乎是SWIG创建.NET包装器及其IDisposable实现的方式的副作用,使用HandleRefs而不是像SafeHandle这样的东西,根据文档“处理”它:
平台调用操作会自动增加由SafeHandle封装的句柄的引用计数,并在完成时减少它们。这样可以确保手柄不会被意外回收或关闭。
更多信息here。
不想进入创建我们自己的SWIG类型映射或编译SWIG新版本的业务,.NET提供了一种保持垃圾收集器对象“活着”的方法。也就是说,在我们将要访问的所有对象上调用GC.KeepAlive
来自优化过程的 end 的P / Invoke(在我们的例子中是Solver和我们的变量),防止垃圾收集器认为它们是可收集的,直到KeepAlive
方法的范围结束,没有副作用(根据他们的文档)。
初步测试表明这一点可行,但考虑到之前它已经间歇性发生,我们将继续观察这种情况。
展望未来,我认为要求SWIG使用SafeHandle
s可能是最好的想法(已经讨论before并且仍然是一个未解决的问题)或更改要使用的类型映射直接SafeHandle
,可能是最好的选择。我可能会尝试自己调查后面的选项,但是因为这个修复程序最终只为我们的代码库添加了3行代码(加上一系列注释),看起来像是一个完整的修复程序,它对我来说将是低优先级。也就是说,对于即将推出的版本来说,修复此问题会很好。