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

Far*_*yev 7 .net c# garbage-collection .net-core .net-standard

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

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

到现在为止还挺好。一件奇怪的事情是,在对该库进行了一些使用之后,我们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)
Run Code Online (Sandbox Code Playgroud)

我已经知道与以下内容相关的消息 garbage collected delegate. 看起来,在某个地方,指向委托的指针被传递给非托管库,然后 GC 收集它。

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

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

我的问题是:

  1. .net framework 和 .net core 在垃圾收集器机制方面有什么区别吗?
  2. .net 框架和 .net 核心怎么可能以不同的方式对同一个库做出反应?

Far*_*yev 5

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

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

.net Framework 和 .net core 怎么可能以不同的方式对同一个库做出反应?

老实说,第一眼我就认为 .net 标准库在任何地方都会以相同的方式表现出来。但是,我当然错了。

让我们从 的“定义”开始.Net Standard.NET Standard只是一个规范(将其视为接口),它只是声明特定平台根据版本公开哪些类型和 API。

如果您看一下,您将看到您的标准库引用了 .NET Standard SDK,其中包含netstandard.dllAPI,或者更好地说,我们可以在库项目中使用的契约。如果您查看带有 的标准库Ildasm.exe,您会发现它正在使用.netstandard.dll.

在此输入图像描述

让我们检查一下我们的核心和框架应用程序如何使用它。而且在核心中它比框架工作得更好。

我一直是图表的粉丝:

在此输入图像描述

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

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

在此输入图像描述

从 msdn阅读有关类型转发的更多信息。

有关详细信息的来源.NET Standard


现在谈谈我的第一个问题:

.net框架和.net core在垃圾收集机制方面有什么区别吗?

事实上,微软不断发展GC机制并不奇怪。


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

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

  • 非常感谢您的这篇文章及其答案。显然你在这上面花了很多时间。一个请求... 作为 P4API.NET 的当前维护者,我非常有兴趣确切地知道您必须做出哪些更改才能解决此问题,以便我可以将它们合并到下一个版本中。您可以提供源代码更改吗?非常感谢! (2认同)