This dump file has an exception of interest stored in it. The stored exception information can be accessed via .ecxr. (bf8.5dc4): Access violation - code c0000005 (first/second chance not available) For analysis of this file, run !analyze -v clr!WKS::gc_heap::mark_object_simple1+0x220: 00007ffb`380453c4 833a00 cmp dword ptr [rdx],0 ds:00007ffa`35451300=????????从卦中又看到了经典的 mark_object_simple1 方法,这个方法是GC用来做对象标记之用的,所以大概率又是托管堆损坏,真是无语了,接下来用 !verifyheap 检查下托管堆。
0:083> !verifyheap object 00000218e96963d8: bad member 00000218E9696450 at 00000218E9696420 Last good object: 00000218E96963C0. Could not request method table data for object 00000218E9696450 (MethodTable: 00007FFA35451300). Last good object: 00000218E96963D8.一看这卦就很不吉利,真的是有对象的mt是不对的,至此我们把崩溃的直接原因给找到了。
0:083> !do 00000218e96963d8 Name: System.Threading.Tasks.Task+DelayPromise MethodTable: 00007ffb3542b3e8 EEClass: 00007ffb3567c7c0 Size: 120(0x78) bytes File: C:\Windows\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll Fields: ... 00007ffb35451300 40035d5 48 ...m.Threading.Timer 0 instance 00000218e9696450 Timer 0:083> dp 00000218e9696450 L6 00000218`e9696450 00007ffa`35451301 00000000`00000000 00000218`e9696460 00000218`e96964c8 00000000`00000000 00000218`e9696470 00007ffb`353e4b51 00000218`e9696368仔细观察卦中对象 00000218e9696450 所显示的mt,你会发现一个是 00007ffb35451300,一个是 00007ffa35451301,很显然前者是对的,后者是错的,可以分别用 !dumpmt 做个验证。
0:083> !dumpmt 00007ffb35451300 EEClass: 00007ffb356942f0 Module: 00007ffb353b1000 Name: System.Threading.Timer mdToken: 0000000002000504 File: C:\Windows\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll BaseSize: 0x20 ComponentSize: 0x0 Slots in VTable: 23 Number of IFaces in IFaceMap: 1 0:083> !dumpmt 00007ffa35451301 00007ffa35451301 is not a MethodTable细心的朋友会发现虽然两个mt地址不一样,但已经非常相近,看样子又是一例经典的bit位翻转,我去,用 .formats 转成二进制观察一下,截图如下:
inline BOOL gc_heap::gc_mark(uint8_t* o, uint8_t* low, uint8_t* high, int condemned_gen) { if ((o >= low) && (o < high)) { BOOL already_marked = marked(o); if (already_marked) { return FALSE; } set_marked(o); return TRUE; } } #define marked(i) header(i)->IsMarked() BOOL IsMarked() const { return !!(((size_t)RawGetMethodTable()) & GC_MARKED); }有了这段源码,这个 bit 为什么为 1 就能轻松的解释了,所以这个翻转是一个正常情况。
2.远离辐射环境