.net 标准库在 .net 核心中失败但在框架中失败

.net standard library fails in .net core but not in framework

我们必须使用来自第 3 方供应商 (perforce) 的 api。直到今天,我们才能够在 .net 框架应用程序中引用和使用 API。但是,现在我们正在重构我们的产品,当然我们决定使用新的 .net 环境,即 .net core 2.2。由于 Perforce 没有为 .net 核心发布该库,我们决定将该库移植到 .net 标准。

所以,简而言之,我们下载了源代码,移植并添加为 .net 核心项目中的参考。

到目前为止,还不错。奇怪的是,在使用该库后,我们从该库中获取 ExecutionEngineException,这会触发 Environment.Failfast 并终止应用程序。

一个更重要的信息是该库使用另一个本地库(p4bridge.dll)。

异常是这样的:

FailFast:
A callback was made on a garbage collected delegate of type 'p4netapi!Perforce.P4.P4CallBacks+LogMessageDelegate::Invoke'.

   at Perforce.P4.P4Bridge.RunCommandW(IntPtr, System.String, UInt32, Boolean, IntPtr[], Int32)
   at Perforce.P4.P4Bridge.RunCommandW(IntPtr, System.String, UInt32, Boolean, IntPtr[], Int32)
   at Perforce.P4.P4Server.RunCommand(System.String, UInt32, Boolean, System.String[], Int32)
   at Perforce.P4.P4Command.RunInt(Perforce.P4.StringList)
   at Perforce.P4.P4CommandResult..ctor(Perforce.P4.P4Command, Perforce.P4.StringList)
   at Perforce.P4.P4Command.Run(Perforce.P4.StringList)
   at Perforce.P4.Client.runFileListCmd(System.String, Perforce.P4.Options, System.String, Perforce.P4.FileSpec[])
   at Perforce.P4.Client.SyncFiles(System.Collections.Generic.IList`1<Perforce.P4.FileSpec>, Perforce.P4.Options)

我已经知道与 garbage collected delegate 相关的消息。似乎在某个地方指向委托的指针被传递给非托管库,然后 GC 收集了它。

我们看一下那个api的源代码。我们看到了一些可能导致该错误的地方。但是,这只是一个想法。

在调查故障时,我们创建了另一个引用该移植库的 .net 框架应用程序,然后 然后我们没有在 .net 框架中遇到任何错误。

我的问题是:

  1. .net framework和.net core在垃圾回收机制上有区别吗
  2. .net framework 和 .net core 怎么可能以不同的方式对同一个库做出反应?

我想 post 回答我的问题,因为我已经解决了这个问题。当您现在阅读我的回答时,这意味着您遇到了类似的问题。首先,我要感谢@MarcGravell的评论,并建议您阅读评论。

首先,想总结一下第二题的答案:

How is that possible that, .net framework and .net core reacts to the same library in a different ways?

老实说,乍一看我在想 .net 标准库在任何地方都会以相同的方式运行。但是,我当然错了。

让我们从 .Net Standard 的 "defintion" 开始。 .NET Standard 只不过是 规范(将其视为接口),它只是声明了哪些类型和 API 由特定平台取决于版本。

如果您看一下,您会发现您的标准库引用了包含 API 的 netstandard.dll 的 .NET Standard SDK,或者更确切地说,contract,我们可以在库项目中使用。如果您查看带有 Ildasm.exe 的标准库,您会发现它使用的是 .netstandard.dll.

让我们看看我们的核心和框架应用程序是如何使用它的。在核心中它比框架更好。

我一直是图表的粉丝:

如图所示,核心应用和框架应用都引用了它们自己的netstandard.dll。这些库是基于 type forwarding 概念构建的。 对于核心应用程序,BCL 类型由 System.Runtime.dll 提供,而对于框架应用程序,BCL 类型由 mscorlib.dll 提供。所以,两个不同的实现

例如,这里是 .netstandard 库的 IL 代码,将被核心应用程序使用:

详细了解 type forwarding from msdn

Source 关于 .NET Standard 的详细信息。


关于我的第一个问题:

Is there any difference between .net framework and .net core in terms of garbage collector mechanism?

其实微软不断进化GC机制也不足为奇。


现在我是如何解决这个问题的:

幸好我移植到标准的库是开源的。我调查了这个问题,简而言之,他们正在将委托指针传递给非托管库。并且该非托管库保存指针并尝试在比该指针的生命周期更长的某个生命周期内使用它。实际上,有趣的一点是框架 GC 没有以某种方式收集该委托,这就是为什么框架端没有异常。但是,在核心 GC 的情况下收集该委托并为失败创建原因。我确实改变了我设置该字段的方式,现在它可以工作了。我将该字段声明为静态并在静态构造函数中对其进行初始化,因此该委托的生命周期与应用程序生命周期一样长。