【发布时间】:2022-06-15 21:09:28
【问题描述】:
我正面临一个 .Net 服务器应用程序,它几乎每周都会因“GC 终结器线程”中的问题而崩溃,更确切地说是在“mscorlib.dll ...~DestroyScout()”的第 798 行,根据 Visual Studio。
Visual Studio 还尝试打开文件“DynamicILGenerator.gs”。我没有这个文件,但我找到了那个文件的一个版本,其中第 798 行确实在析构函数或 DestroyScout 内(不管这可能意味着什么)。
我的 Visual Studio 环境中有以下信息:
线程:
Not Flagged > 5892 0 Worker Thread GC Finalizer Thread mscorlib.dll!System.Reflection.Emit.DynamicResolver.DestroyScout.~DestroyScout
调用栈:
[Managed to Native Transition]
> mscorlib.dll!System.Reflection.Emit.DynamicResolver.DestroyScout.~DestroyScout() Line 798 C#
[Native to Managed Transition]
kernel32.dll!@BaseThreadInitThunk@12() Unknown
ntdll.dll!__RtlUserThreadStart() Unknown
ntdll.dll!__RtlUserThreadStart@8() Unknown
Locals(无法确定 $exception 对象是否正确):
+ $exception {"Exception of type 'System.ExecutionEngineException' was thrown."} System.ExecutionEngineException
this Cannot obtain value of the local variable or argument because it is not available at this instruction pointer,
possibly because it has been optimized away. System.Reflection.Emit.DynamicResolver.DestroyScout
Stack objects No CLR objects were found in the stack memory range of the current frame.
“DynamicILGenerator.cs”的源代码,提到DestroyScout类(注释中提到了第798行):
private class DestroyScout
{
internal RuntimeMethodHandleInternal m_methodHandle;
[System.Security.SecuritySafeCritical] // auto-generated
~DestroyScout()
{
if (m_methodHandle.IsNullHandle())
return;
// It is not safe to destroy the method if the managed resolver is alive.
if (RuntimeMethodHandle.GetResolver(m_methodHandle) != null)
{
if (!Environment.HasShutdownStarted &&
!AppDomain.CurrentDomain.IsFinalizingForUnload())
{
// Somebody might have been holding a reference on us via weak handle.
// We will keep trying. It will be hopefully released eventually.
GC.ReRegisterForFinalize(this);
}
return;
}
RuntimeMethodHandle.Destroy(m_methodHandle); // <===== line 798
}
}
观察窗口 (m_methodHandle):
m_methodHandle Cannot obtain value of the local variable or argument because
it is not available at this instruction pointer,
possibly because it has been optimized away.
System.RuntimeMethodHandleInternal
一般转储模块信息:
Dump Summary
------------
Dump File: Application_Server2.0.exe.5296.dmp : C:\Temp_Folder\Application_Server2.0.exe.5296.dmp
Last Write Time: 14/06/2022 19:08:30
Process Name: Application_Server2.0.exe : C:\Runtime\Application_Server2.0.exe
Process Architecture: x86
Exception Code: 0xC0000005
Exception Information: The thread tried to read from or write to a virtual address
for which it does not have the appropriate access.
Heap Information: Present
System Information
------------------
OS Version: 10.0.14393
CLR Version(s): 4.7.3920.0
Modules
-------
Module Name Module Path Module Version
----------- ----------- --------------
...
clr.dll C:\Windows\Microsoft.NET\Framework\v4.0.30319\clr.dll 4.7.3920.0
...
注意:转储到达 Windows-Server 2016 计算机上,我正在我的 Windows-10 环境中调查转储(不要误会OS Version 在转储摘要中)!
有人有想法吗?
【问题讨论】:
-
对我来说,这似乎是多线程场景中的竞争条件,其中多个线程处理同一个对象句柄
-
竞争条件?在我无法访问的某个来源中?有什么方法可以解决这个问题(这是一个已知的错误,是否可以跟踪它的进展,...)?
-
再看一遍,我认为它与多线程无关,但它显然看起来像一个错误是的。在析构函数中重新注册
this以完成最终确定可能会导致 GC 再次调用析构函数.. 这是什么?这是在 C# 中销毁对象的奇怪逻辑,等到所有弱引用都放弃了它们的句柄。我不知道,抱歉评论 -
您是否尝试过使用较新版本的 .NET Framework?
ExecutionEngineException对我来说可能是某种损坏的内存,它恰好只在最终确定时才出现。您使用的是unsafe还是 PInvoke?
标签: c# dump windows-server-2016