Managed Code에서 "Attempted to read or write protected memory. This is often an indication that other memory is corrupt." 와 같은 오류가 발생하는 것은 흔하지 않다. 이것은 Native Code에서 잘못된 메모리를 참조하는 경우에 발생하는 데, 아시다시피 Managed환경에서는 포인터를 이용한 직접적인 메모리를 다루는 경우가 거의 없기 때문에 경험할 일이 없을 것이다. 하지만, PInvoke 와 같은 Interop 를 사용하는 경우라면 달라질 수 있다. 이는 결국 Native COM을 Managed 에서 사용하는 것이므로, 여전히 Native COM에서의 문제가 Managed환경으로 전달되었을 때, Access Violation의 위험성이 있는 것이다. 결국, Pageheap을 enable 하거나 해서 Crash Dump를 다시 잡는 것이 필요할 수도 있다. 일단, Memory Dump를 확인하면 문제가 발생한 Callstack에 아래와 같은 System.AccessViolationException을 볼 수 있다.
0:131> !dso
OS Thread Id: 0xacc (131)
RSP/REG Object Name
0000000027bda3f0 00000008d0fff488 System.Threading.Thread
0000000027bda438 00000008d0fff488 System.Threading.Thread
0000000027bda588 00000009710807f8 System.String
0000000027bda5a8 00000009710807f8 System.String
0000000027bda5b0 0000000971080908 System.String
0000000027bda668 0000000971080908 System.String
0000000027bda7d0 00000008d100adc8 System.String
0000000027bda7f8 00000008d100ca20 System.String
0000000027bda840 00000008d100b930 System.String
0000000027bda900 00000008d100b930 System.String
0000000027bda9c0 00000008d0fff7c0 System.String
0000000027bda9c8 00000008d0fff7c0 System.String
0000000027bdaaf0 00000008d10095f8 System.String
0000000027bdab08 00000008d100ca20 System.String
0000000027bdab68 00000008d100ca20 System.String
0000000027bdab80 00000008d0fff340 System.AccessViolationException
0000000027bdabe0 00000008d0fff340 System.AccessViolationException
0000000027bdad28 00000008d0fff340 System.AccessViolationException
0000000027bdb0f0 00000008d0ffd308 System.String
0000000027bdb108 00000008d0ffd290 System.String
0000000027bdb110 00000008d0ffd2b0 System.String
0000000027bdb138 00000008d0ffd270 System.String
0000000027bdb140 00000008d0ffd240 System.String
0000000027bdb148 00000008d0ffd208 System.String
0000000027bdb680 00000008d0fff340 System.AccessViolationException
0000000027bdb910 00000008d0fff340 System.AccessViolationException
0000000027bdb938 00000008d0fff340 System.AccessViolationException
. . .
그리고, 먼저, !verifyheap 을 통해서 Managed Heap을 Check 하는 것도 필요하다.
0:131> !verifyheap
-verify will only produce output if there are errors in the heap
------------------------------
Heap 0
object 0000000880ff00d0: does not have valid MT
curr_object : 0000000880ff00d0
Last good object: 0000000880ff00b0
----------------
total 4 objects
출력된 결과는 curr_object가 corruption되었다는 것과 메모리 영역에서 가장 가까운 Object중에 정상적인 Object의 address를 알려준다. 그러므로, curr_object 를 살펴보면 invalid 하다는 결과를 얻는다.
0:131> !do 0000000880ff00d0
<Note: this object has an invalid CLASS field>
Invalid object
0:131> !do 0000000880ff00b0
Name: System.String
MethodTable: 00000642784365a0
EEClass: 000006427803e4f0
Size: 32(0x20) bytes
GC Generation: 0
(C:\WINDOWS\assembly\GAC_64\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll)
String: AES
Fields:
MT Field Offset Type VT Attr Value Name
0000000000000000 4000096 8 System.Int32 1 instance 4 m_arrayLength
0000000000000000 4000097 c System.Int32 1 instance 3 m_stringLength
0000000000000000 4000098 10 System.Char 1 instance 41 m_firstChar
0000000000000000 4000099 20 System.String 0 shared static Empty
>> Domain:Value 00000000d75a2aa0:NotInit Unable to get AppDomain d7900cc0
0000000000000000 400009a 28 SZARRAY 0 shared static WhitespaceChars
>> Domain:Value 00000000d75a2aa0:NotInit Unable to get AppDomain d7900cc0
정상적인 Data를 같이 보여주는 것은 GC에서는 Memory Allocation이 순차적으로 일어난다는 것과 무관하지 않다. low address에서 아래와 같이 Check 하여 Data를 살펴보거나 해당 Object의 MethodTable 정보를 Check 하는 것은 개발자가 관련있는 Code를 verify 하는 데 도움이 될 수 있기 때문이다.
0:131> dc 0000000880ff00b0
00000008`80ff00b0 784365a0 00000642 00000004 00000003 .eCxB........... <--- valid Object
00000008`80ff00c0 00450041 00000053 00000000 00000000 A.E.S...........
00000008`80ff00d0 7843e5e0 00000642 0000000d 00000000 ..CxB........... <--- invalid Object
00000008`80ff00e0 32313338 30323031 .................
또한 !gcroot 에 대한 결과로 관련된 Object 등을 Check 할 수 있는 데, 아래의 경우는 조금 실망스러운 결과이다.
0:131> !gcroot 0000000880ff00b0
Note: Roots found on stacks may be false positives. Run "!help gcroot" for
more info.
Scan Thread 52 OSThread 1440
Scan Thread 79 OSThread f4c
Scan Thread 145 OSThread 1f64
Scan Thread 149 OSThread 144c
Scan Thread 99 OSThread 18e4
Scan Thread 148 OSThread 1d38
Scan Thread 93 OSThread 1c0c
Scan Thread 91 OSThread 149c
Scan Thread 146 OSThread 1980
Scan Thread 96 OSThread 1dac
Scan Thread 136 OSThread f84
Scan Thread 98 OSThread 6ac
RSP:33c6cbb8:Root: 0000000880ff00b0(System.String)
RSP:33c6cd88:Root: 0000000880ff00b0(System.String)
RSP:33c6ce28:Root: 0000000880ff00b0(System.String)
RSP:33c6cfc0:Root: 0000000880ff00b0(System.String)
Scan Thread 106 OSThread 1a10
Scan Thread 108 OSThread 1ce4
Scan Thread 122 OSThread 190c
Scan Thread 121 OSThread 1698
Scan Thread 110 OSThread 14a8
Scan Thread 107 OSThread 1c10
Scan Thread 116 OSThread 1b80
Scan Thread 117 OSThread 141c
Scan Thread 131 OSThread acc
Scan Thread 135 OSThread 6e8
Scan Thread 126 OSThread 1d1c
Scan Thread 132 OSThread 1e18
해당 Object가 존재하는 98번 Thread에서 연관된 Callstack을 Check 할 수 있다. 하지만, Native에서도 마찮가지로 Heap Corruption이 발생한 것은 Dumping 시점 이전에 문제가 발생한 것이 이후에 해당 Managed Heap의 사용에 의해 AV가 발생한 경우가 많기 때문에 문제가 정확히 드러나지 않을 수 있다. 그러므로, 다소 시간을 걸리더라도 Pageheap을 enable 하고 여러 차례 Dump를 수집할 필요가 있을 지도 모른다. 그리고, 1st chance AV 및 기타Exception에 대해서도 Callstack의 Check 라던가 관련성 여부를 살펴보는 것이 필요할 수 있다.
'Programming > C#/Xna/Kinect/WPF' 카테고리의 다른 글
RGB 색상표 (16진수) 변환 (0) | 2013.05.29 |
---|---|
XNAExtras로 XBOX360에 폰트를 출력해 보자!! #1 (0) | 2013.05.28 |
C# StreamReader 에서의 한글 Encoding 문제 (0) | 2013.05.28 |
[XNA] Scrolling background images horizontally across the screen (0) | 2013.05.08 |
[XNA] A Simple 2D Camera (0) | 2013.05.08 |