Yong Hee Park's Blog

Developer Support Engineer for Internet [MSFT]

ASP.Net 2.0 (Whidbey) 에서 Hang Dump 분석

ASP.Net 2.0 (Whidbey) 에서 Hang Dump 분석

  • Comments 1

이전 포스팅에서 Tess의 IIS 6.0 + ASP.Net 1.1 이하 버젼에서의 Hang Dump 분석과 관련된 정보를 올렸습니다.

비교적(겨우 2년 전이네요 :-) 최근에 Tess의 블로그에 ASP.Net 2.0 에서 같은 맥락으로 Hang Dump 분석시 참고가 되는 글이 올라와서 같이 번역(사실 거의 복사에 가깝습니다만) 해서 올립니다.

 

Tess의 글에서 언급하고 있습니다만 서버 프로세스가 처리를 하지 않거나 메모리 사용량이 늘어나거나 CPU 점유율이 높아지면서 Hang Dump를 수집하게 되면 고객들 께서는 "무슨 일을 하기에" 그런 일이 벌어지는지 문의를 하십니다.

바로 이전 포스팅과 본 포스팅은 "무슨일" 이 아니라 "나머지 무시할 수 있는 것"들에 대한 얘기 입니다. 즉, 사용자의 Request를 처리하지 않는 "Normal"한 (또는 Idle 상태의) Thread들은 어떻게 생겼는가 에 대해서 언급하고 있습니다.

 

일단 이전 포스팅에서 IIS 6.0의 W3WP 프로세스의 Thread들이 소개 되어 있기 때문에 간단하게 넘기고 여기서는 제목 처럼 .Net Framework 2.0(또는 ASP.Net 2.0)에서 이전의 .Net Framework 1.1과 달라진 부분에 집중 해 보겠습니다.

 

우선 놀고 있는 CLR Worker Thread를 보죠.

Idle CLR Worker Thread

16 Id: efc.a00 Suspend: 1 Teb: fff88000 Unfrozen
ChildEBP RetAddr Args to Child
0219fc84 7d4d8c56 00000228 00000000 0219fcc8 ntdll!ZwWaitForSingleObject+0x15
0219fcf4 79e718fd 00000228 00009c40 00000000 kernel32!WaitForSingleObjectEx+0xac
0219fd38 79e718c6 00000228 00009c40 00000000 mscorwks!PEImage::LoadImage+0x199
0219fd88 79e7187c 00009c40 00000000 00000000 mscorwks!CLREvent::WaitEx+0x117
0219fd98 79f5e51b 00009c40 00000000 00000000 mscorwks!CLREvent::Wait+0x17
0219fe18 79f8b1c5 001880e0 00009c40 00000000 mscorwks!ThreadpoolMgr::SafeWait+0x73
0219fe94 79f7997f 00000000 00000000 00000000 mscorwks!ThreadpoolMgr::WorkerThreadStart+0xf5
0219ffb8 7d4dfff1 0019c440 00000000 00000000 mscorwks!ThreadpoolMgr::intermediateThreadProc+0x49
0219ffec 00000000 79f79939 0019c440 00000000 kernel32!BaseThreadStart+0x34
 
혹시 이전 번젼과 차이가 느껴지시나요? 참고를 위해서 이전 버젼의 CLR Worker Thread의 Stack Trace를 비교해 보시죠.
이전 포스팅에서 잠시 언급을 했습니다만, .Net Framework 1.1은 GC Version이 서로 많이 다르고
서버 프로세스와 일반 클라이언트 프로세스에 로딩 되는 DLL 역시 바뀝니다.
 
ASP.Net 2.0에서는 서버 프로세스에서도 mscrowks (Workstation version)이 올라가고 있다는 뜻일까요? 그렇지는 않습니다.
이는 현재 구현상 이름이 남아 있는 것 뿐이 실행시 모양은 차이가 있습니다.
아래 GC Thread 부분을 참고하세요.
 

Idle CLR WorkerThread for ASP.Net 1.1

  11  Id: fb8.268 Suspend: 0 Teb: 7ffaa000 Unfrozen
ChildEBP RetAddr  Args to Child             
0199fdf8 7c822124 77e6baa8 00000234 00000000 ntdll!KiFastSystemCallRet
0199fdfc 77e6baa8 00000234 00000000 0199fe40 ntdll!NtWaitForSingleObject+0xc
0199fe6c 77e6ba12 00000234 00009c40 00000000 kernel32!WaitForSingleObjectEx+0xac
0199fe80 791d401f 00000234 00009c40 00000000 kernel32!WaitForSingleObject+0x12
0199fea4 791fdacc 00000000 00000000 80a56bcc mscorsvr!ThreadpoolMgr::WorkerThreadStart+0x3a
0199ffb8 77e66063 000b6da8 00000000 00000000 mscorsvr!ThreadpoolMgr::intermediateThreadProc+0x44

0199ffec 00000000 791fda8b 000b6da8 00000000 kernel32!BaseThreadStart+0x34

 
Idle CLR Completion Port/IO Thread
14 Id: efc.11c8 Suspend: 1 Teb: fff8e000 Unfrozen
ChildEBP RetAddr Args to Child
0209fe7c 7d50664c 00000234 0209fee8 0209fec0 ntdll!NtRemoveIoCompletion+0x15
0209fea8 79f795de 00000234 0209feec 0209fee8 kernel32!GetQueuedCompletionStatus+0x29
0209ff14 79f7997f 00000000 00000000 00000000 mscorwks!ThreadpoolMgr::CompletionPortThreadStart+0x11a
0209ffb8 7d4dfff1 0019c440 00000000 00000000 mscorwks!ThreadpoolMgr::intermediateThreadProc+0x49
0209ffec 00000000 79f79939 0019c440 00000000 kernel32!BaseThreadStart+0x34
 

 

Idle CLR Gate Thread

15 Id: efc.1534 Suspend: 1 Teb: fff8b000 Unfrozen
ChildEBP RetAddr Args to Child
0211fe18 7d4d0ec5 00000000 0211fe58 00000000 ntdll!ZwDelayExecution+0x15
0211fe80 79f56b45 000001f4 00000000 fcffff56 kernel32!SleepEx+0x68
0211feb4 79f56b15 000001f4 00000000 fcffff0a mscorwks!EESleepEx+0xa3
0211fee8 79f405ed 000001f4 00000000 79f569e7 mscorwks!__DangerousSwitchToThread+0x70
0211fef4 79f569e7 000001f4 9e2c9368 000003f4 mscorwks!__SwitchToThread+0xb
0211ffb8 7d4dfff1 00000000 00000000 00000000 mscorwks!ThreadpoolMgr::GateThreadStart+0xa1
0211ffec 00000000 79f56952 00000000 00000000 kernel32!BaseThreadStart+0x34
 

위에서 언급했던 Server GC와 Workstation GC의 차이는 아래의 Stack Trace에서 차이가 납니다.

 

Idle GC Thread

18 Id: efc.12b8 Suspend: 1 Teb: fff82000 Unfrozen
ChildEBP RetAddr Args to Child
0257fe6c 7d4d8c56 000002dc 00000000 00000000 ntdll!ZwWaitForSingleObject+0x15
0257fedc 79e718fd 000002dc ffffffff 00000000 kernel32!WaitForSingleObjectEx+0xac
0257ff20 79e718c6 000002dc ffffffff 00000000 mscorwks!PEImage::LoadImage+0x199
0257ff70 79e7187c ffffffff 00000000 00000000 mscorwks!CLREvent::WaitEx+0x117
0257ff80 7a0d6f16 ffffffff 00000000 00000000 mscorwks!CLREvent::Wait+0x17
0257ffa8 7a0d722e 00000000 fcb9fe5a 0257ffec mscorwks!SVR::gc_heap::gc_thread_function+0x2f
0257ffb8 7d4dfff1 001b20e8 00000000 00000000 mscorwks!SVR::gc_heap::gc_thread_stub+0x9b

0257ffec 00000000 7a0d7192 001b20e8 00000000 kernel32!BaseThreadStart+0x34
 
아래의 Stack Trace는 Client Application 상에서 실행되고 있는 GC Thread의 Snapshot 입니다,.
특히, 붉게 표시된 부분은 GC가 위의 Thread와 달리 열심히 살아 있는 (즉, 사용되고 있는) 객체를 표시하고 있는 중이라는 것을 보실 수 있습니다.
위의 내용과 비교해 보시면 mscorwks!SVR이 아니네요.
 

ChildEBP RetAddr
0776fa8c 68d05dda mscorwks!WKS::gc_heap::mark_object_simple1+0x148
0776fab8 68c9f515 mscorwks!WKS::gc_heap::mark_object_simple+0x19d
0776faec 68c9efc1 mscorwks!WKS::gc_heap::c_drain_mark_list+0x95
0776fb18 68c9f9b3 mscorwks!WKS::gc_heap::c_mark_phase+0xaa

0776fb34 68d0ed65 mscorwks!WKS::gc_heap::gc1+0x59
0776fb4c 68d0edb7 mscorwks!WKS::gc_heap::gc_thread_function+0x9f
0776fb54 75e04911 mscorwks!WKS::gc_heap::gc_thread_stub+0x73

0776fb60 76e3e4b6 KERNEL32!BaseThreadInitThunk+0xe
0776fba0 76e3e489 ntdll!__RtlUserThreadStart+0x23
0776fbb8 00000000 ntdll!_RtlUserThreadStart+0x1b

 

Idle Finalizer Thread

GC와 떨어져서 언급 할 수 없는 Finalizer의 경우도 역시 마찬가지 입니다.

 

20 Id: efc.132c Suspend: 1 Teb: fff7c000 Unfrozen
ChildEBP RetAddr Args to Child
0267fcd0 7d4e1cda 00000002 0267fd1c 00000001 ntdll!NtWaitForMultipleObjects+0x15
0267fd78 7d4e3e16 00000002 7a398698 00000000 kernel32!WaitForMultipleObjectsEx+0x11a
0267fd94 7a0849d8 00000002 7a398698 00000000 kernel32!WaitForMultipleObjects+0x18
0267fdb4 7a085307 001b0c60 0267fe6c 0267feb4 mscorwks!SVR::WaitForFinalizerEvent+0x7a
0267fdc8 79ed890c 0267feb4 00000000 00000001 mscorwks!SVR::GCHeap::FinalizerThreadWorker+0x75
0267fdd8 79ed88aa 0267feb4 0267fe60 79f54f64 mscorwks!Thread::UserResumeThread+0xfb
0267fe6c 79ed87d1 0267feb4 fc89ff4a 00000000 mscorwks!Thread::DoADCallBack+0x355
0267fea8 79ed976c 0267feb4 00000000 001cad20 mscorwks!Thread::DoADCallBack+0x541
0267fed0 79ed9737 7a085292 00000008 7a0854b0 mscorwks!ManagedThreadBase_NoADTransition+0x32
0267fedc 7a0854b0 7a085292 fc89fef6 00000000 mscorwks!ManagedThreadBase::FinalizerBase+0xb
0267ff14 79ed8d16 00000000 00000000 00000000 mscorwks!SVR::GCHeap::FinalizerThreadStart+0xbb
0267ffb8 7d4dfff1 001b0ca8 00000000 00000000 mscorwks!Thread::intermediateThreadProc+0x49
0267ffec 00000000 79ed8cd0 001b0ca8 00000000 kernel32!BaseThreadStart+0x34
 

Idle CLR Debugger Thread

17 Id: efc.1964 Suspend: 1 Teb: fff85000 Unfrozen
ChildEBP RetAddr Args to Child
022cfe34 7d4e1cda 00000003 022cfe80 00000001 ntdll!NtWaitForMultipleObjects+0x15
022cfedc 7d4e3e16 00000003 022cff20 00000000 kernel32!WaitForMultipleObjectsEx+0x11a
022cfef8 79f0cb1e 00000003 022cff20 00000000 kernel32!WaitForMultipleObjects+0x18
022cff58 79f0ca7b fcc2fe6a 00000000 00000000 mscorwks!DebuggerRCThread::MainLoop+0xcf
022cff88 79f0c9be fcc2fe5a 00000000 00000000 mscorwks!DebuggerRCThread::ThreadProc+0xca
022cffb8 7d4dfff1 00000000 00000000 00000000 mscorwks!DebuggerRCThread::ThreadProcStatic+0x82
022cffec 00000000 79f0c978 00000000 00000000 kernel32!BaseThreadStart+0x34
 

Idle Timer Thread

22 Id: efc.136c Suspend: 1 Teb: fff76000 Unfrozen
ChildEBP RetAddr Args to Child
0284fecc 7d4d0ec5 00000001 0284ff0c 00000000 ntdll!ZwDelayExecution+0x15
0284ff34 79f667c7 00002710 00000001 0284ffa4 kernel32!SleepEx+0x68
0284ffb0 79f66758 00000000 7d4dfff1 0219e75c mscorwks!ThreadpoolMgr::TimerThreadFire+0x6d
0284ffb8 7d4dfff1 0219e75c 00000000 00000000 mscorwks!ThreadpoolMgr::TimerThreadStart+0x54
0284ffec 00000000 79f66702 0219e75c 00000000 kernel32!BaseThreadStart+0x34
 

Idle Appdomain Unload Thread

21 Id: efc.12d8 Suspend: 1 Teb: fff79000 Unfrozen
ChildEBP RetAddr Args to Child
0275fcbc 7d4d8c56 000002d0 00000000 00000000 ntdll!ZwWaitForSingleObject+0x15
0275fd2c 79e718fd 000002d0 ffffffff 00000000 kernel32!WaitForSingleObjectEx+0xac
0275fd70 79e718c6 000002d0 ffffffff 00000000 mscorwks!PEImage::LoadImage+0x199
0275fdc0 79e7187c ffffffff 00000000 00000000 mscorwks!CLREvent::WaitEx+0x117
0275fdd0 79f78d81 ffffffff 00000000 00000000 mscorwks!CLREvent::Wait+0x17
0275fe94 79ed8d16 001babd0 00000000 00000000 mscorwks!AppDomain::ADUnloadThreadStart+0x2fb
0275ffb8 7d4dfff1 001b8670 00000000 00000000 mscorwks!Thread::intermediateThreadProc+0x49
0275ffec 00000000 79ed8cd0 001b8670 00000000 kernel32!BaseThreadStart+0x34
 
이전에는 없던 AppDomain Unload Thread라는 것이 생겼는데요. 관련 설명은 다음의 MSDN URL을 참고하세요.
 
AppDomain.Unload 메서드
http://msdn.microsoft.com/ko-kr/library/system.appdomain.unload.aspx
 

설명

.NET Framework 버전 2.0에는 응용 프로그램 도메인 언로드 전용 스레드가 있습니다. 이 스레드를 사용하면 특히 .NET Framework이 호스팅된 경우 안전성이 향상됩니다. 스레드가 Unload를 호출하면 대상 도메인이 언로드되도록 표시됩니다. 그러면 전용 스레드가 도메인의 언로드를 시도하고 도메인의 모든 스레드가 중단됩니다. 스레드가 비관리 코드를 실행하거나 finally 블록을 실행하고 있는 등의 이유로 중단되지 않는 경우 일정한 시간이 지난 후 원래 Unload를 호출한 스레드에서 CannotUnloadAppDomainException이 throw됩니다. 중단할 수 없는 스레드가 결국 종료되면 대상 도메인은 언로드되지 않습니다. 따라서 .NET Framework 버전 2.0에서는 실행 중인 스레드를 종료시키지 못할 수 있으므로 domain이 언로드되지 않을 수도 있습니다.

 

Blog - Comment List MSDN TechNet
  • Loading...
Leave a Comment
  • Please add 8 and 2 and type the answer here:
  • Post