성태의 닷넷 이야기
홈 주인
모아 놓은 자료
프로그래밍
질문/답변
사용자 관리
사용자
메뉴
아티클
외부 아티클
유용한 코드
온라인 기능
MathJax 입력기
최근 덧글
[정성태] The Windows Registry Adventure #1: ...
[정성태] systemd for Developers I ; https:/...
[정성태] 엄밀히 object 타입의 인스턴스가 다른 타입으로 형변환 가능...
[정성태] 아래의 글에서 나오는 "Windows Application Pa...
[정성태] The history of calling conventions,...
[정성태] Secure and Deploy .NET Windows Form...
[정성태] Get Started with Milvus Vector DB i...
[정성태] cyberark/PipeViewer - A tool that...
[정성태] WinForms in a 64-Bit world – our st...
[정성태] 예제에서 SELECT_SQL도 내부적으로는 SqlCommand/...
글쓰기
제목
이름
암호
전자우편
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 - !threads 출력 결과로부터 닷넷 관리 스레드(System.Threading.Thread) 객체를 구하는 방법</h1> <p> 모든 스레드를 열거하는 가장 쉬운 방법으로 !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:017> <span style='color: blue; font-weight: bold'>!threads</span> ThreadCount: 298 UnstartedThread: 0 BackgroundThread: 298 PendingThread: 0 DeadThread: 0 Hosted Runtime: no PreEmptive GC Alloc Lock ID OSID ThreadOBJ State GC Context Domain Count APT Exception 26 1 fd4 00117830 1808220 Enabled 406dc694:406dc6b8 07c6bf90 1 MTA (Threadpool Worker) 44 2 dd8 001345c8 b220 Enabled 00000000:00000000 000de1d8 0 MTA (Finalizer) 45 3 db8 03f8fc18 80a220 Enabled 00000000:00000000 000de1d8 0 MTA (Threadpool Completion Port) 46 4 ddc 03fe6c78 1220 Enabled 00000000:00000000 000de1d8 0 Ukn 47 5 de8 05450cd0 b220 Enabled 4ff022a0:4ff022b0 03fe7258 0 MTA 48 6 dc8 058a38e0 200b220 Enabled 4fe61b04:4fe620d8 03fe7258 0 MTA 49 7 a9c 07592be8 200b220 Enabled 3c477948:3c478044 03fe7258 0 MTA 50 8 dbc 075935d8 b220 Enabled 4412dd90:4412dd90 03fe7258 0 MTA 51 9 5b8 07592308 200b220 Enabled 00000000:00000000 03fe7258 0 MTA 52 a 16c8 07625850 80a220 Enabled 00000000:00000000 000de1d8 0 MTA (Threadpool Completion Port) 24 b 1794 07626358 180a220 Enabled 00000000:00000000 000de1d8 0 MTA (Threadpool Worker) 53 c 1738 0762dfe0 b220 Enabled 1616926c:16169274 03fe7258 0 MTA 54 d 1678 0766cc40 200b220 Enabled 00000000:00000000 03fe7258 0 MTA 55 e 10e4 0766bd10 200b220 Enabled 00000000:00000000 03fe7258 0 MTA 56 f 6c 0766dd68 200b220 Enabled 00000000:00000000 03fe7258 0 MTA 57 10 1330 0766f550 180b220 Enabled 4ef9a2c0:4ef9a2c4 07c6bf90 1 MTA (Threadpool Worker) 58 11 208 07670718 188b224 Enabled 43445c70:43445d60 07f41fc8 1 MTA (Threadpool Worker) ...[생략]... </pre> <br /> 그런데 이 정보들로부터 System.Threading.Thread 타입을 구할 수 있는 방법이 없습니다. (혹시 쉽게 구하는 방법을 아시는 분은 덧글 부탁드립니다. ^^)<br /> <br /> 물론 다소 불편하지만 우회 방법은 있습니다. 관리 힙을 전부 뒤져서 System.Threading.Thread 타입인 것을 찾는 것인데 시작은 우선 -mt에 해당하는 MethodTable 값을 찾아야 합니다. 이에 대해서는 전에도 설명했었는데,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > windbg - 닷넷 메모리 덤프에서 전역 객체의 내용을 조사하는 방법 ; <a target='tab' href='http://www.sysnet.pe.kr/2/0/11460'>http://www.sysnet.pe.kr/2/0/11460</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;' > 0:017> <span style='color: blue; font-weight: bold'>!name2ee mscorlib!System.Threading.Thread</span> Module: 02d32010 (mscorlib.dll) Token: 0x02000154 <span style='color: blue; font-weight: bold'>MethodTable: 043117dc</span> EEClass: 02db3280 Name: System.Threading.Thread </pre> <br /> 이렇게 구한 MethodTable == 0x43117dc를 dumpheap 명령어에 전달하면, 관리 힙에 할당되어 있는 System.Threading.Thread 타입의 인스턴스를 모두 열람해 줍니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > 0:017> <span style='color: blue; font-weight: bold'>!DumpHeap -mt 043117dc</span> ------------------------------ Heap 0 Address MT Size 100b1c24 043117dc 56 1019450c 043117dc 56 101ad1b4 043117dc 56 101ad5b4 043117dc 56 101ad804 043117dc 56 101ada00 043117dc 56 10271920 043117dc 56 10283be8 043117dc 56 10283f3c 043117dc 56 10284180 043117dc 56 10284494 043117dc 56 103334f8 043117dc 56 10354f28 043117dc 56 10441584 043117dc 56 10451968 043117dc 56 1053a824 043117dc 56 105c7fe4 043117dc 56 106139b0 043117dc 56 10613d04 043117dc 56 10613f48 043117dc 56 1061425c 043117dc 56 ...[생략]... </pre> <br /> 출력 결과에 나온 각각의 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:017> <span style='color: blue; font-weight: bold'>!do 100b1c24</span> Name: System.Threading.Thread MethodTable: 043117dc EEClass: 02db3280 Size: 56(0x38) bytes (C:\WINDOWS\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll) Fields: MT Field Offset Type VT Attr Value Name 05d011f4 4000640 4 ....Contexts.Context 0 instance 141c6858 m_Context 05d0fb08 4000641 8 ....ExecutionContext 0 instance 31df6ee0 m_ExecutionContext 02d3914c 4000642 c System.String 0 instance 00000000 m_Name 04310bb4 4000643 10 System.Delegate 0 instance 00000000 m_Delegate 05f0e400 4000644 14 System.Object[][] 0 instance 1084adc0 m_ThreadStaticsBuckets 0493cc30 4000645 18 System.Int32[] 0 instance 1084addc m_ThreadStaticsBits 0431677c 4000646 1c ...ation.CultureInfo 0 instance 00000000 m_CurrentCulture 0431677c 4000647 20 ...ation.CultureInfo 0 instance 00000000 m_CurrentUICulture 02d36d5c 4000648 24 System.Object 0 instance 00000000 m_ThreadStartArg 0431698c 4000649 28 System.IntPtr 1 instance <span style='color: blue; font-weight: bold'>117830 DONT_USE_InternalThread</span> 043c9a54 400064a 2c System.Int32 1 instance 2 m_Priority 043c9a54 400064b 30 System.Int32 1 instance <span style='color: blue; font-weight: bold'>1 m_ManagedThreadId</span> 0493e488 400064c 16c ...LocalDataStoreMgr 0 shared static s_LocalDataStoreMgr >> Domain:Value 000de1d8:00000000 03fe7258:1a0b1d2c 0778f8c0:00000000 07c6bf90:00000000 07e6d3d0:00000000 07eb6318:00000000 07f41fc8:00000000 080977e0:00000000 0812b6f0:00000000 0814feb8:00000000 082a2228:1d154ca0 083bea88:00000000 2c9ba550:00000000 0835c508:00000000 2cc681a0:00000000 2d157008:00000000 2d84be60:00000000 2d8b07b8:00000000 2d9d1c10:00000000 2da783e0:00000000 2daf2008:00000000 2db19ff0:00000000 08359a40:00000000 2dc1eea8:1476a408 2dd59f48:00000000 2ddfa9b0:00000000 2cc617e8:00000000 2df14d18:00000000 << 02d36d5c 400064d 170 System.Object 0 shared static s_SyncObject >> Domain:Value 000de1d8:100b1c18 03fe7258:100b5334 0778f8c0:140b2f24 07c6bf90:141c91c4 07e6d3d0:190b422c 07eb6318:142ec160 07f41fc8:143e1aec 080977e0:101b45b4 0812b6f0:1028a610 0814feb8:1e0b4510 082a2228:10377148 083bea88:1c0e63b8 2c9ba550:1047b448 0835c508:10552bcc 2cc681a0:18116530 2d157008:14380520 2d84be60:18219410 2d8b07b8:1069b6f8 2d9d1c10:182f6058 2da783e0:107c3890 2daf2008:12109898 2db19ff0:10625e0c 08359a40:1713b278 2dc1eea8:1c24aa14 2dd59f48:1a19071c 2ddfa9b0:1d1c87ac 2cc617e8:1f1b7e34 2df14d18:1d2e5a0c << </pre> <br /> DONT_USE_InternalThread 값이 !threads 목록에 있는 것과 같다는 것을 알 수 있습니다. <br /> <br /> 그런데... 스레드가 한두 개라면 모를까, 일반적인 프로그램에서 그 많은 스레드의 객체를 일일이 저렇게 뒤져보는 것도 일입니다. 따라서 이런 경우에는 pykd의 도움을 받아 스크립트로 만들어 두면 됩니다. 관련 스크립트의 힌트는 다음에서 이미 설명했었습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > windbg - 풀 덤프에서 .NET 스레드의 상태를 알아내는 방법 ; <a target='tab' href='http://www.sysnet.pe.kr/2/0/11269'>http://www.sysnet.pe.kr/2/0/11269</a> </pre> <br /> 따라서 이 글에 저 스크립트를 적용하면 다음과 같이 모든 Thread 타입의 관련 값을 열거할 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > 0:006> .foreach ($t {!dumpheap -mt 043117dc -short}) { .printf " Thread Obj ${$t} and the Thread Id is %N \n",poi(${$t}+4c) } </pre> <br /> 또는 pykd를 이용하면 좀 더 구체적으로 결과를 뽑아낼 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > windbg에서 python 스크립트 실행하는 방법 - pykd ; <a target='tab' href='http://www.sysnet.pe.kr/2/0/11227'>http://www.sysnet.pe.kr/2/0/11227</a> </pre> <br /> 즉, 다음과 같이 thread ID를 기준으로 System.Threading.Thread 객체를 구할 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > from pykd import * <span style='color: blue; font-weight: bold'>findId = "7670718"</span> def getItem(text, key): for line in text.splitlines(): if key in line: result = line.split(":")[1].strip() return result def GetManagedId(text): for line in text.splitlines(): items = line.split() if len(items) >= 7 and <span style='color: blue; font-weight: bold'>items[7] == "DONT_USE_InternalThread"</span>: return items[6] return "NOT FOUND" outputText = pykd.dbgCommand("!name2ee mscorlib!System.Threading.Thread") mtThread = getItem(outputText, "MethodTable:") outputText = pykd.dbgCommand("!DumpHeap -mt " + mtThread) for line in outputText.splitlines(): items = line.split() if len(items) == 3: threadAddress = items[0].strip() threadText = pykd.dbgCommand("!do " + threadAddress) managedId = GetManagedId(threadText) if managedId != "NOT FOUND": if managedId == findId: dprintln(threadText) break dprintln ("END") </pre> <br /> 그런데... 시간이 좀 오래 걸린다는 흠이 있긴 합니다. ^^ 참고로, 위의 명령어를 응용하면 Managed Thread Id 값을 알고 있는 상태에서 그것의 System.Threading.Thread 인스턴스를 구하는 것도 가능합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > from pykd import * <span style='color: blue; font-weight: bold'>findId = "17"</span> def getItem(text, key): for line in text.splitlines(): if key in line: result = line.split(":")[1].strip() return result def GetManagedId(text): for line in text.splitlines(): items = line.split() if len(items) >= 7 and <span style='color: blue; font-weight: bold'>items[7] == "m_ManagedThreadId"</span>: return items[6] return "NOT FOUND" outputText = pykd.dbgCommand("!name2ee mscorlib!System.Threading.Thread") mtThread = getItem(outputText, "MethodTable:") outputText = pykd.dbgCommand("!DumpHeap -mt " + mtThread) for line in outputText.splitlines(): items = line.split() if len(items) == 3: threadAddress = items[0].strip() threadText = pykd.dbgCommand("!do " + threadAddress) managedId = GetManagedId(threadText) if managedId != "NOT FOUND": if managedId == findId: dprintln(threadText) break dprintln ("END") </pre> </p><br /> <br /><hr /><span style='color: Maroon'>[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]</span> </div>
첨부파일
스팸 방지용 인증 번호
4147
(왼쪽의 숫자를 입력해야 합니다.)