성태의 닷넷 이야기
홈 주인
모아 놓은 자료
프로그래밍
질문/답변
사용자 관리
사용자
메뉴
아티클
외부 아티클
유용한 코드
온라인 기능
MathJax 입력기
최근 덧글
[정성태] Detecting blocking calls using asyn...
[정성태] 아쉽게도, 커뮤니티는 아니고 개인 블로그입니다. ^^
[정성태] 질문이 잘 이해가 안 됩니다. 우선, 해당 소스코드에서 ILis...
[양승조
] var대신 dinamic으로 선언해서 해결은 했습니다. 맞는 해...
[양승조
] 또 막혔습니다. ㅠㅠ var list = props[i].Ge...
[양승조
] 아. 감사합니다. 어제는 안됐던것 같은데....정신을 차려야겠네...
[정성태] "props[i].GetValue(props[i])" 코드에서 ...
[정성태] 저렇게 조각 코드 말고, 실제로 재현이 되는 예제 프로젝트를 압...
[정성태] Modules 창(Ctrl+Shift+U)을 띄워서, 해당 Op...
[정성태] 만드실 수 있습니다. 단지, Unity 엔진 내의 스크립트와 W...
글쓰기
제목
이름
암호
전자우편
HTML
홈페이지
유형
제니퍼 .NET
닷넷
COM 개체 관련
스크립트
VC++
VS.NET IDE
Windows
Team Foundation Server
디버깅 기술
오류 유형
개발 환경 구성
웹
기타
Linux
Java
DDK
Math
Phone
Graphics
사물인터넷
부모글 보이기/감추기
내용
<div style='display: inline'> <h1 style='font-family: Malgun Gothic, Consolas; font-size: 20pt; color: #006699; text-align: center; font-weight: bold'>windbg에서 확인해 보는 관리 힙의 인스턴스 구조</h1> <p> 이 글은 다음의 내용을 windbg로 재현한 것입니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > C#에서 확인해 보는 관리 힙의 인스턴스 구조 ; <a target='tab' href='http://www.sysnet.pe.kr/2/0/1176'>http://www.sysnet.pe.kr/2/0/1176</a> </pre> <br /> 또는 아래의 내용에 대한 좀 더 자세한 확인 방법이라고 소개하면 될 것 같군요. ^^<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > .NET 참조 개체 인스턴스의 Object Header를 확인하는 방법 ; <a target='tab' href='http://www.sysnet.pe.kr/2/0/1175'>http://www.sysnet.pe.kr/2/0/1175</a> </pre> <br /> <hr style='width: 50%' /><br /> <br /> windbg로 필드를 하나도 갖지 않는 경우 분석해 보면 다음과 같은 결과가 나옵니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > 0:004> .loadby sos clr 0:004> <span style='color: blue; font-weight: bold'>!name2ee ConsoleApplication1!ConsoleApplication1.Program</span> Module: 00292e9c Assembly: ConsoleApplication1.exe Token: 02000002 MethodTable: <span style='color: blue; font-weight: bold'>00293810</span> EEClass: 00291424 Name: ConsoleApplication1.Program 0:004> <span style='color: blue; font-weight: bold'>!dumpheap -mt 00293810</span> Address MT Size <span style='color: blue; font-weight: bold'>026cbf90</span> 00293810 12 total 0 objects Statistics: MT Count TotalSize Class Name 00293810 1 12 ConsoleApplication1.Program Total 1 objects 0:004> <span style='color: blue; font-weight: bold'>!do 026cbf90</span> Name: ConsoleApplication1.Program MethodTable: 00293810 EEClass: 00291424 Size: <span style='color: blue; font-weight: bold'>12(0xc) bytes</span> File: D:\...\ConsoleApplication1.exe Fields: None 0:004> <span style='color: blue; font-weight: bold'>dd 026cbf90</span> 026cbf90 <span style='color: blue; font-weight: bold'>00293810 00000000</span> 00000000 00000000 026cbfa0 00000000 00000000 00000000 00000000 </pre> <br /> 필드를 하나도 갖고 있지 않는 Program 타입의 클래스가 new로 할당되었을 때 12바이트가 관리 힙에 할당됨을 위의 결과에서 알 수 있는데요. 그러면서 메모리를 덤프하기 위해 "dd 026cbf90"라는 명령어를 내리고 그 내용으로 다음과 같은 분석을 할 수 있는데,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > xxxxxxxx: (0x26cbf90 - 4바이트에 위치한) Object Header(SyncBlock Index) 00293810: MethodTable 00000000: (필드가 하나도 없어도 1개는 기본 예약) </pre> <br /> <hr style='width: 50%' /><br /> <br /> Object Header에 SyncBlock 인덱스가 사용되고 있는 경우를 확인하기 위해 예제를 다음과 같이 만들어 보았습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > using System; using System.Threading; class MyClassA { public int _a = 1; } class MyClassB { public int _a = 2; public int _b = 3; } class MyClassC { public int _a = 4; public int _b = 5; public int _c = 6; } class Program { static void Main(string[] args) { MyClassA mca = new MyClassA(); MyClassB mcb = new MyClassB(); MyClassC mcc = new MyClassC(); lock (mca) lock (mcb) lock (mcc) { new Thread(func).Start(mca); new Thread(func).Start(mcb); new Thread(func).Start(mcc); Console.WriteLine("Console.ReadLine..."); Console.ReadLine(); } } private static void func(object obj) { lock (obj) { Console.ReadLine(); } } } </pre> <br /> Console.ReadLine까지 실행되었을 때 windbg로 붙여서 다음과 같이 mca, mcb, ccc 객체의 값을 검사할 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > 0:007> <span style='color: blue; font-weight: bold'>.loadby sos clr</span> 0:007> <span style='color: blue; font-weight: bold'>!name2ee *!MyClassA</span> Module: 720c1000 Assembly: mscorlib.dll -------------------------------------- Module: 00852ed4 Assembly: ConsoleApplication1.exe Token: 02000002 MethodTable: <span style='color: blue; font-weight: bold'>00853828</span> EEClass: 00851368 Name: MyClassA 0:007> <span style='color: blue; font-weight: bold'>!dumpheap -mt 00853828</span> Address MT Size <span style='color: blue; font-weight: bold'>025424ac</span> 00853828 12 Statistics: MT Count TotalSize Class Name 00853828 1 12 MyClassA Total 1 objects 0:007> <span style='color: blue; font-weight: bold'>!do 025424ac</span> Name: MyClassA MethodTable: 00853828 EEClass: 00851368 Size: 12(0xc) bytes File: d:\...\ConsoleApplication1.exe Fields: MT Field Offset Type VT Attr Value Name 724d3c50 4000001 4 System.Int32 1 instance 1 _a </pre> <br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > 0:007> <span style='color: blue; font-weight: bold'>!name2ee *!MyClassB</span> Module: 720c1000 Assembly: mscorlib.dll -------------------------------------- Module: 00852ed4 Assembly: ConsoleApplication1.exe Token: 02000003 MethodTable: <span style='color: blue; font-weight: bold'>0085389c</span> EEClass: 008513bc Name: MyClassB 0:007> <span style='color: blue; font-weight: bold'>!dumpheap -mt 0085389c</span> Address MT Size <span style='color: blue; font-weight: bold'>025424b8</span> 0085389c 16 Statistics: MT Count TotalSize Class Name 0085389c 1 16 MyClassB Total 1 objects 0:007> <span style='color: blue; font-weight: bold'>!do 025424b8 </span> Name: MyClassB MethodTable: 0085389c EEClass: 008513bc Size: 16(0x10) bytes File: d:\...\ConsoleApplication1.exe Fields: MT Field Offset Type VT Attr Value Name 724d3c50 4000002 4 System.Int32 1 instance 2 _a 724d3c50 4000003 8 System.Int32 1 instance 3 _b </pre> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > 0:007> <span style='color: blue; font-weight: bold'>!name2ee *!MyClassC</span> Module: 720c1000 Assembly: mscorlib.dll -------------------------------------- Module: 00852ed4 Assembly: ConsoleApplication1.exe Token: 02000004 MethodTable: <span style='color: blue; font-weight: bold'>0085391c</span> EEClass: 00851410 Name: MyClassC 0:007> <span style='color: blue; font-weight: bold'>!dumpheap -mt 0085391c</span> Address MT Size <span style='color: blue; font-weight: bold'>025424c8</span> 0085391c 20 Statistics: MT Count TotalSize Class Name 0085391c 1 20 MyClassC Total 1 objects 0:007> <span style='color: blue; font-weight: bold'>!do 025424c8 </span> Name: MyClassC MethodTable: 0085391c EEClass: 00851410 Size: 20(0x14) bytes File: d:\...\ConsoleApplication1.exe Fields: MT Field Offset Type VT Attr Value Name 724d3c50 4000004 4 System.Int32 1 instance 4 _a 724d3c50 4000005 8 System.Int32 1 instance 5 _b 724d3c50 4000006 c System.Int32 1 instance 6 _c </pre> <br /> 이를 통해서 mca, mcb, mcc 변수의 객체 할당이 각각 025424ac, 025424b8, 025424c8 주소에 되었으며 그 사이의 바이트 간격을 조사해 보면 정확히 mca, mcb 크기와 일치하는 것을 볼 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > 0:007> <span style='color: blue; font-weight: bold'>? 025424b8 - 025424ac</span> Evaluate expression: 12 = 0000000c 0:007> <span style='color: blue; font-weight: bold'>? 025424c8 - 025424b8</span> Evaluate expression: 16 = 00000010 </pre> <br /> 즉, 3개의 변수가 관리 힙에 연속해서 할당되어 있습니다. 이 상태에서 첫 번째 mca 변수의 "Address" 주소로 덤프를 하면 다음과 같습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > 0:007> <span style='color: blue; font-weight: bold'>db 025424ac</span> 025424ac <span style='color: blue; font-weight: bold'>28 38 85 00 01 00 00 00</span>-05 00 00 08 9c 38 85 00 (8...........8.. 025424bc 02 00 00 00 03 00 00 00-06 00 00 08 1c 39 85 00 .............9.. 025424cc 04 00 00 00 05 00 00 00-06 00 00 00 00 00 00 00 ................ 025424dc 64 c4 4d 72 dc 24 54 02-00 00 00 00 b4 05 af 04 d.Mr.$T......... 025424ec 60 c0 85 00 00 00 00 00-00 00 00 00 01 00 00 08 `............... 025424fc 60 2e 4d 72 00 00 00 00-00 00 00 00 00 00 00 00 `.Mr............ 0254250c 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 0254251c 30 fd b2 00 02 00 00 00-03 00 00 00 01 00 00 00 0............... 28 38 85 00: 0x00853828 - MethodTable 01 00 00 00: 0x00000001 - int _a 필드 값 </pre> <br /> 그리고 025424ac 주소의 4바이트 이전 값을 확인해 보면,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > 0:007> db 025424ac - 4 L4 025424a8 04 00 00 08 </pre> <br /> SyncBlock의 인덱스 번호가 나옵니다. 따라서 "db 025424ac" 출력 결과를 완전하게 분석하면 다음과 같습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > 04 00 00 08: 0x08000004 - mca 객체의 SyncBlock 인덱스 28 38 85 00: 0x00853828 - MethodTable(MyClassA) 01 00 00 00: 0x00000001 - int _a 필드 값 05 00 00 08: 0x08000005 - mcb 객체의 SyncBlock 인덱스 9c 38 85 00: 0x0085389c - MethodTable(MyClassB) 02 00 00 00: 0x00000002 - int _a 필드 값 03 00 00 00: 0x00000003 - int _b 필드 값 06 00 00 08: 0x08000006 - mcc 객체의 SyncBlock 인덱스 1c 39 85 00: 0x0085391c - MethodTable(MyClassC) 04 00 00 00: 0x00000004 - int _a 필드 값 05 00 00 00: 0x00000005 - int _b 필드 값 06 00 00 00: 0x00000006 - int _c 필드 값 </pre> <br /> sos.dll에는 SyncBlock 인덱스 값에 대한 내용도 볼 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > 0:007> !SyncBlk Index SyncBlock MonitorHeld Recursion Owning Thread Info SyncBlock Owner 4 00b30308 3 1 00b092a0 34e0 0 025424ac MyClassA 5 00b3033c 3 1 00b092a0 34e0 0 025424b8 MyClassB 6 00b30370 3 1 00b092a0 34e0 0 025424c8 MyClassC ----------------------------- Total 6 CCW 0 RCW 0 ComClassFactory 0 Free 0 </pre> <br /> 위의 필드에서 Owing Thread 정보를 보면 "00b092a0 34e0" 값을 확인할 수 있는데, 이는 !threads 명령어를 통해 확인할 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > 0:007> !threads ThreadCount: 5 UnstartedThread: 0 BackgroundThread: 1 PendingThread: 0 DeadThread: 0 Hosted Runtime: no Lock ID OSID ThreadOBJ State GC Mode GC Alloc Context Domain Count Apt Exception 0 1 <span style='color: blue; font-weight: bold'>34e0 00b092a0</span> 2a020 Preemptive 0254522C:00000000 00afda00 4 MTA 3 2 2ff4 00b17920 2b220 Preemptive 00000000:00000000 00afda00 0 MTA (Finalizer) 4 3 28c4 00b2fd30 202b020 Preemptive 00000000:00000000 00afda00 0 MTA 5 4 3158 00b33f80 202b020 Preemptive 00000000:00000000 00afda00 0 MTA 6 5 3368 00b34e58 202b020 Preemptive 00000000:00000000 00afda00 0 MTA </pre> <br /> 즉, SyncBlock 4, 5, 6번 인덱스에 해당하는 객체들의 잠금을 소유하고 있는 스레드는 00b092a0번에 해당하는 것으로 해석할 수 있습니다.<br /> <br /> 참고로, 4바이트의 Object Header 공간은 ComData, AppDomainID, Hashcode 등을 담기도 합니다. 하지만 그런 식으로 사용되다가 lock을 하게 되면 <a href='https://www.sysnet.pe.kr/2/0/1175#n2img'>지난 글의 두 번째 그림</a>에서 보인 "SyncBlock"을 만들고 기존 Object Header의 값을 SyncBlock으로 옮긴 후 그것에 대한 Index 값을 Object Header에 쓰게 됩니다. 아래의 글에 보면 이러한 과정을 "Header Inflation"이라고 설명하고 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > C# 클래스 객체는 어떻게 Managed Heap에 표현되는가? ; <a target='tab' href='http://www.csharpstudy.com/network/DevNote/Article/5'>http://www.csharpstudy.com/network/DevNote/Article/5</a> </pre> <br /> 이 글의 내용을 이해했다면 재미있는 생각을 해볼 수 있습니다. 가령 관리 힙의 시작/끝 주소를 안다면 그 힙에 포함된 모든 객체의 정보를 덤프하는 것도 가능하다는 이야기입니다. ^^<br /> </p><br /> <br /><hr /><span style='color: Maroon'>[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]</span> </div>
첨부파일
스팸 방지용 인증 번호
8794
(왼쪽의 숫자를 입력해야 합니다.)