我想知道是否有人遇到过与我相同的情况,NullReferenceException
发生在一个不可能的地方。
这里有完全相同的代码段抛出异常:
private readonly StatePair[] _pairs =
{
new StatePair(0),
new StatePair(1),
new StatePair(2)
};
public void CommitAll()
{
var states = new State[_pairs.Length];
// collect in reverse order
for (var i = _pairs.Length - 1; i >= 0; i--)
{
// The only exit of CaptureState() method is a "new State()" statement.
states[i] = _pairs[i].CaptureState();
if (states[i] == null)
throw new ApplicationException("The state captured is null.");
}
// commit in normal order
foreach (var s in states)
{
if (s == null)
throw new ApplicationException("The state is null.");
s.Commit(); // *** NullReferenceException ***
}
}
void Run() // Thread start
{
while (true)
{
CommitAll();
Thread.Sleep(200);
}
}
堆栈跟踪:
System.NullReferenceException: Object reference not set to an instance of an object.
at ...SystemUpdateCoordinator.CommitAll() in ...SystemUpdateCoordinator.cs:line 217
at ...SystemUpdateCoordinator.Run() in ...SystemUpdateCoordinator.cs:line 22
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
从堆栈跟踪中我们可以告诉s.Commit()
抛出NullReferenceException
所以似乎s
为空,但我们已经检查了空并抛出ApplicationException
在每个CaptureState()
之后。如果CaptureState
现在返回,我们应该从ApplicationException
的正文中获取for
,而不是NullReferenceException
内的foreach
。
可怕的是,并非所有用户都获得异常(它是WPF应用程序)。我们有大约10个用户运行这个新版本,其中只有4个符合错误,但它在两天内多次发生。我们在一家大公司工作,因此所有用户的环境都受到限制,应该是相同的(.NET 4.0,Win 7)。
此处还有一些可能有用的细节:
是否涉及多线程?
是的,但唯一可能同时访问的部分是MyPair
对象,而在CaptureState
方法中,它保存来自ReaderWriterLockSlim
的编写器锁。我仔细检查了MyPair
中的其他方法,并且所有方法都受到同一ReaderWriterLockSlim
实例的读者锁定的保护。此外,CaptureState()
每次都会返回新实例。所有其余变量都是本地的(如s
),他们不会遇到线程问题。
任何其他相关错误同时发生?
是的,实际上在应用程序的新版本发生了另一个错误,这是一个访问冲突错误。它应与this one相同,但由于两个原因,我不能100%确定NullReferenceException
的原因:
NullReferenceException
的内存,为什么它总是会发生在同一个语句中呢?为什么它不会在其他地方发生?这个问题困扰了我好几天。我认为它是一个运行时问题,但这不是我可以证明或证明其他人错误的东西。我还尝试稍微更改CommitAll()
方法,看看我们是否可以获得不同的汇编代码。
如果我有更多信息,我会在这里发布更新。
====更新1(20150603)====
有人质疑这条痕迹是否准确,我认为是。
首先,CommitAll()
方法没有内联。我已经转储了汇编代码,它调用Commit
方法而没有内联。
此外,首先,此处没有throw new ApplicationException()
检查。代码如下所示,因为这里不可能为null:
public void CommitAll()
{
var states = new State[_pairs.Length];
for (var i = _pairs.Length - 1; i >= 0; i--)
{
states[i] = _pairs[i].CaptureState();
}
foreach (var s in states)
{
s.Commit(); // <- Line 209
}
}
堆栈跟踪指向第209行,即s.Commit()
。所以我添加了一些空检查,堆栈跟踪变为第217行,这正是同一语句的新位置。
====更新2(20150609)====
崩溃只发生在过去一周,但奇怪的是WER(Windows错误报告)没有产生迷你崩溃转储。事件日志仍然说:
应用程序:MyApp.exe
框架版本:v4.0.30319
说明:由于.NET运行时在IP 000007FEEC0F25E8(000007FEEC0B0000)中出现内部错误而导致进程终止,退出代码为80131506.
与之前的错误日志不同,显示它是访问冲突。用户说他没有看到WER对话框,所以应用程序突然崩溃了。
所以我只能检查旧崩溃中的旧转储。
其中一人说这是一个着名的并发GC问题&#34;:
This dump file has an exception of interest stored in it.
The stored exception information can be accessed via .ecxr.
(2c90.381c): Access violation - code c0000005 (first/second chance not available)
clr!WKS::gc_heap::mark_object_simple+0x19a:
000007fe`eb13dc87 f70100000080 test dword ptr [rcx],80000000h ds:00000000`00000000=????????
0:008> kb
RetAddr : Args to Child : Call Site
000007fe`eb13dd8e : 00000000`b2103c48 00000000`2c92d850 00000000`2c92e9c0 00000000`b2023f08 : clr!WKS::gc_heap::mark_object_simple+0x19a
000007fe`eb1de7be : 00000000`b2103c48 00000000`2c92e9c0 00000000`2c92c2e0 00000000`2c92d7b0 : clr!WKS::GCHeap::Promote+0x79
000007fe`eb1e04ec : 00000000`2c92bec0 00000000`00000007 00000000`00000002 00000000`00000071 : clr!GcEnumObject+0x37
000007fe`eb1dfdd5 : 000007fe`00000000 00000000`00000000 00000000`00000000 000007fe`00000008 : clr!GcInfoDecoder::EnumerateLiveSlots+0x5dd
000007fe`eb1dea47 : 00000000`00080000 00000000`00000000 00000000`0230b540 00000000`2c92c2e0 : clr!EECodeManager::EnumGcRefs+0x13d
000007fe`eb09109f : 00000000`00000000 000007ff`02668548 00000000`2c92d7b0 00000000`00000000 : clr!GcStackCrawlCallBack+0x1e2
000007fe`eb090a6b : 00000000`2c92cb50 00000000`00000000 00000000`00000002 00000000`00000000 : clr!Thread::MakeStackwalkerCallback+0x2f
000007fe`eb0900f2 : 00000000`1fc3ab10 00000000`1fc3ab10 000000f8`00000000 00000000`00000002 : clr!Thread::StackWalkFramesEx+0x8d
000007fe`eb1de6e8 : 00000000`00000000 00000000`00000001 00000000`00000000 00000000`1fc3ab10 : clr!Thread::StackWalkFrames+0xb1
000007fe`eb13d831 : 00000000`00000000 00000000`2c92d880 00000000`00000000 00000000`023ade80 : clr!CNameSpace::GcScanRoots+0x1a4
000007fe`eb13de6d : 00000000`00000000 00000000`00000000 000007fe`eb8ea160 000007fe`eb13e6b6 : clr!WKS::gc_heap::mark_phase+0xe1
000007fe`eb29fcfd : 00000107`e77ad732 00000000`2c92d959 00000000`00000000 00000000`00000000 : clr!WKS::gc_heap::gc1+0xae
000007fe`eb13e44e : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : clr!WKS::gc_heap::garbage_collect+0x42e
000007fe`eb13d3fe : 00000000`00000030 00000000`00000002 000007fe`eb060000 00000000`00000000 : clr!WKS::GCHeap::GarbageCollectGeneration+0x14e
000007fe`eb13d12e : 00000000`0000001d 00000000`b2526b80 00000000`00000002 00000000`00000030 : clr!WKS::gc_heap::try_allocate_more_space+0x25f
000007fe`eb08d418 : 000007fe`e8b93028 00000000`00000030 00000000`00000002 00000000`2c92ddf0 : clr!FastAllocateObject+0x73e
Unable to load image C:\Windows\assembly\NativeImages_v4.0.30319_64\System.Core\84fa340f30d1921e0d8817f9344ee367\System.Core.ni.dll, Win32 error 0n2
*** WARNING: Unable to verify checksum for System.Core.ni.dll
000007fe`e8b25049 : 000007fe`e8b93028 00000000`b2526b00 00000000`b2526b00 000007fe`e8b24f9a : clr!JIT_NewFast+0xb8
Unable to load image C:\Windows\assembly\NativeImages_v4.0.30319_64\mscorlib\79d73b390cca60b8a1c1d1228c771f2f\mscorlib.ni.dll, Win32 error 0n2
*** WARNING: Unable to verify checksum for mscorlib.ni.dll
000007fe`ea18e458 : 00000000`b2526b00 00000000`00000004 00000000`b2526b00 00000000`00000000 : System_Core_ni+0x2a5049
000007fe`e8b37280 : 000007fe`e88849d8 000007fe`ea17efb0 00000000`0328be48 00000000`b24ee798 : mscorlib_ni+0x3ae458
000007ff`027790bc : 000007fe`e88dc738 00000000`b2524ed0 00000000`03137038 00000000`2c92dde8 : System_Core_ni+0x2b7280
000007ff`027789a0 : 00000000`00000000 00000000`00000000 000007ff`03b5ba48 00000000`067059f0 : 0x7ff`027790bc
...
000007fe`ea15169c : 00000000`04118280 00000000`0416ea50 00000000`0416ea50 00000000`00000000 : 0x7ff`024799c0
000007fe`ea1515ab : 00000000`0416ea50 00000000`00000000 00000000`00000000 000007fe`eb0a5a1f : mscorlib_ni+0x37169c
000007fe`ea1e6d8d : 00000000`0416ea50 00000000`00000000 00000000`00000000 00000000`00000000 : mscorlib_ni+0x3715ab
000007fe`eb09c9e4 : 00000000`0416ea78 00000000`00000000 00000000`00000000 00000000`00000000 : mscorlib_ni+0x406d8d
000007fe`eb09caf9 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : clr!CallDescrWorker+0x84
000007fe`eb09cb75 : 00000000`2c92ef48 00000000`00000001 00000000`2c92ef50 00000000`2c92f1a0 : clr!CallDescrWorkerWithHandler+0xa9
000007fe`eb09d0ac : 00000000`2c92f198 000007fe`ea0e4860 00000000`2c92f230 000007fe`e9eace7c : clr!MethodDesc::CallDescr+0x2a1
000007fe`eb16de50 : 00000000`2c92f640 00000000`2c92f220 00000000`2c92f6e0 000007fe`ea2bdf28 : clr!MethodDesc::CallTargetWorker+0x44
000007fe`eb1008e6 : 00000000`1fc3ab10 00000000`2c92f640 00000000`1fc3ab10 00000000`00001000 : clr!ThreadNative::KickOffThread_Worker+0x148
000007fe`eb10087b : 00000000`00000000 00000000`1fc3ab10 ffffffff`fffffffe 00000000`1fc3ab10 : clr!QueueUserWorkItemManagedCallback+0x92
000007fe`eb1007e8 : 00000000`00000480 00000000`004d0000 00000000`00000000 00000000`00000478 : clr!PEDecoder::CheckILOnlyImportDlls+0x294
000007fe`eb10094b : ffffffff`ffffffff 00000000`1fc3ab10 00000000`00000000 00000000`00000000 : clr!StubLinkerCPU::X86EmitPushReg+0x135
000007fe`eb16dca0 : 00000000`1fc3ab10 00000000`2c92fd80 00000000`00000001 00000000`00000000 : clr!COMArrayInfo::GetReference+0x12b
000007fe`eb22c736 : 00000000`28ef64b0 00000000`2c92f6f8 00000000`1fc3ab10 00000000`772cb98e : clr!ThreadNative::KickOffThread+0xc0
00000000`771959cd : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : clr!Thread::intermediateThreadProc+0x7d
00000000`772cb891 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : kernel32!BaseThreadInitThunk+0xd
00000000`00000000 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : ntdll!RtlUserThreadStart+0x1d
另一个说不同的东西:
This dump file has an exception of interest stored in it.
The stored exception information can be accessed via .ecxr.
(1714.ed4): Access violation - code c0000005 (first/second chance not available)
clr!VirtualCallStubManager::ResolveWorker+0x4a3:
000007fe`edb827d8 488b8980000000 mov rcx,qword ptr [rcx+80h] ds:00000101`00000c84=????????????????
0:012> kb
RetAddr : Args to Child : Call Site
000007fe`edb82713 : 00000000`00e2f360 00000000`2c50e740 00000000`00000000 800003ff`825b7314 : clr!VirtualCallStubManager::ResolveWorker+0x4a3
000007fe`edb43585 : 00000000`00000003 000007ff`0442a6b0 00000000`a004a410 00000000`8bd38210 : clr!VirtualCallStubManager::ResolveWorkerStatic+0x213
000007ff`02b416fb : 00000000`b7476e68 00000000`2c50e910 00000000`00e2bfd0 00000000`00000000 : clr!ResolveWorkerAsmStub+0x95
000007ff`02b41344 : 00000000`0a48bc20 00000000`a0444b88 00000000`8bd37108 000007fe`edbe45e4 : 0x7ff`02b416fb
...
000007ff`0245b040 : 00000000`000000fa 00000000`04157e38 00000000`045a09d0 00000000`00000000 : 0x7ff`0245b3e4
Unable to load image C:\Windows\assembly\NativeImages_v4.0.30319_64\mscorlib\79d73b390cca60b8a1c1d1228c771f2f\mscorlib.ni.dll, Win32 error 0n2
*** WARNING: Unable to verify checksum for mscorlib.ni.dll
000007fe`ea7e169c : 00000000`0431c4a0 00000000`045a09d0 00000000`045a09d0 00000000`00000000 : 0x7ff`0245b040
000007fe`ea7e15ab : 00000000`045a09d0 00000000`00000000 00000000`00000000 000007fe`edb85a1f : mscorlib_ni+0x37169c
000007fe`ea876d8d : 00000000`045a09d0 00000000`00000000 00000000`00000000 00000000`00000000 : mscorlib_ni+0x3715ab
000007fe`edb7c9e4 : 00000000`045a09f8 00000000`00000000 00000000`00000000 00000000`00000000 : mscorlib_ni+0x406d8d
000007fe`edb7caf9 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : clr!CallDescrWorker+0x84
000007fe`edb7cb75 : 00000000`2c50f168 00000000`00000001 00000000`2c50f170 00000000`2c50f3c0 : clr!CallDescrWorkerWithHandler+0xa9
000007fe`edb7d0ac : 00000000`2c50f3b8 000007fe`ea774860 00000000`2c50f450 000007fe`ea53ce7c : clr!MethodDesc::CallDescr+0x2a1
000007fe`edc4de50 : 00000000`2c50f860 00000000`2c50f440 00000000`2c50f900 000007fe`ea94df28 : clr!MethodDesc::CallTargetWorker+0x44
000007fe`edbe08e6 : 00000000`1c696620 00000000`2c50f860 00000000`1c696620 00000000`00001000 : clr!ThreadNative::KickOffThread_Worker+0x148
000007fe`edbe087b : 00000000`00000000 00000000`1c696620 ffffffff`fffffffe 00000000`1c696620 : clr!QueueUserWorkItemManagedCallback+0x92
000007fe`edbe07e8 : 000007ff`fffdc000 00000000`00000002 00000000`00000002 000007fe`f51f7163 : clr!PEDecoder::CheckILOnlyImportDlls+0x294
000007fe`edbe094b : ffffffff`ffffffff 00000000`1c696620 00000000`00000000 00000000`00000000 : clr!StubLinkerCPU::X86EmitPushReg+0x135
000007fe`edc4dca0 : 00000000`1c696620 00000000`2c50ff20 00000000`00000001 00000000`00000000 : clr!COMArrayInfo::GetReference+0x12b
000007fe`edd0c736 : 00000000`21062e70 00000000`2c50f918 00000000`1c696620 00000000`00000000 : clr!ThreadNative::KickOffThread+0xc0
00000000`76eb59cd : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : clr!Thread::intermediateThreadProc+0x7d
00000000`770eb891 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : kernel32!BaseThreadInitThunk+0xd
00000000`00000000 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : ntdll!RtlUserThreadStart+0x1d
此外,用户使用的是.NET 4.0,但所有开发人员的计算机都使用的是.NET 4.5(但目标是.NET 4.0)。这就解释了为什么GC错误只发生在用户身上。