记一次 .NET Core 程序崩溃问题修复
背景:程序使用 ONNX Runtime 运行AI模型推理,但是仅能使用CPU执行,一旦想使用支持GPU版本的包"Microsoft.ML.OnnxRuntime.DirectML",程序就卡住一会然后崩溃。
引发崩溃的代码如下:
int gpuDeviceId = 0;
var sessionOptions = new SessionOptions()
{
LogSeverityLevel = OrtLoggingLevel.ORT_LOGGING_LEVEL_WARNING,
};
sessionOptions.AppendExecutionProvider_DML(gpuDeviceId);
sessionOptions.GraphOptimizationLevel = GraphOptimizationLevel.ORT_ENABLE_ALL;
var inferenceSession = new InferenceSession(modelParh, sessionOptions);
经过排查,如果使用一个纯净的新项目运行上面代码(同样的 .NET 版本和 ONNX 包版本),可以运行,但是在原项目里就是不行。
并且,为了消除是其它什么地方意外修改了啥导致出现问题,把这段引起崩溃的代码放到Program.cs的 Main函数在程序启动时就执行,也是崩溃。
那么,难道是依赖项导致的问题?这是有可能的,因为ONNX Runtime会使用native的dll,native dll之间发生版本冲突是会导致奇怪问题。
于是使用 WinDBG 分析程序崩溃转储文件"XXXX.Application.Host.exe.dmp",最后的堆栈是:
STACK_TEXT:
0000006404978160 00007ffc8ed4c4cc : 0000025f00000001 0000025f17fc39f8 0000025f17fc39f8 0000025f17fc3a00 : msvcp140!mtx_do_lock+0x9c
00000064049781c0 00007ffc8ed59105 : 00007ffc8efb1de8 0000006404978638 0000025f17fc39f8 0000000000000001 : onnxruntime!OrtSessionOptionsAppendExecutionProvider_CPU+0x63d7bc
0000006404978210 00007ffdaaa9526d : 0000000000000007 0000000000000000 0000000000000000 00007ffdad02bfca : onnxruntime!OrtSessionOptionsAppendExecutionProvider_CPU+0x64a3f5
0000006404978240 00007ffc8ed639ea : 0000000000000000 000000007ffe0384 0000006404978638 00007ffdacfd8b68 : ucrtbase!initterm+0x2d
0000006404978270 00007ffc8ed63b57 : 0000000000000001 0000000000000000 0000000000000000 0000000000000001 : onnxruntime!OrtSessionOptionsAppendExecutionProvider_CPU+0x654cda
00000064049782a0 00007ffdacfd8b5f : 00007ffc8e430000 0000000000000001 0000000000000000 000000007ffe0385 : onnxruntime!OrtSessionOptionsAppendExecutionProvider_CPU+0x654e47
0000006404978300 00007ffdad01d4fd : 0000025f001519c0 00007ffc8e430000 00007ffc00000001 0000000000000000 : ntdll!LdrpCallInitRoutine+0x6b

在对msvcp140的函数调用中出现了崩溃,是指针异常引发的崩溃,为什么当前项目调用这里会崩,而纯净项目不会?于是拿纯净项目输出的bin\runtimes\win-x64文件夹和当前项目一一比对:发现纯净项目下没有msvcp140.dll文件
于是,我试着再次启动原项目,但启动前删除了msvcp140.dll文件,于是好了!
也就是说,原项目有别的地方依赖了msvcp140.dll库,导致这个dll被拷贝到了程序目录,而msvcp140.dll是一个C++运行时,我的系统已经安装过,因此即使程序目录下没有,也会自动去系统安装目录找到并加载;但是由于我程序目录有了,它从当前目录加载;
那么可能ONNX的GPU版刚好也依赖msvcp140.dll,但是dll版本有细微差异,导致了内部指针异常。
最终经过排查,也确实如此,尝试升级了项目对msvcp140.dll的依赖版本后,问题解决。
浙公网安备 33010602011771号