Microsoft MVP성태의 닷넷 이야기
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일
 
(연관된 글이 1개 있습니다.)

windbg 분석 사례 - 닷넷 프로파일러의 GC 콜백 부하

희한한 현상이 발생했습니다. 새로 개발한 닷넷 프로파일러가 설치되면 "Performance Monitor" MMC에서 "ASP.NET v4.0.30319" 범주의 "Requests Queued"에 큐잉 현상이 발생하는 것입니다.

현상이 발생하는 PC에서 Process Explorer를 통해 살펴보면 유독 다음과 같은 식의 콜 스택이 자주 보이는 것을 확인할 수 있었습니다.

ntdll.dll!ZwWaitForSingleObject+0xa
KERNELBASE.dll!WaitForSingleObjectEx+0x98
clr.dll!CoUninitializeEE+0x27eef
clr.dll!CoUninitializeEE+0x27ea3
clr.dll!CoUninitializeEE+0x27e64
clr.dll!GetMetaDataInternalInterface+0x327b9
clr.dll!ClrCreateManagedInstance+0x2e13
KERNEL32.DLL!BaseThreadInitThunk+0x22
ntdll.dll!RtlUserThreadStart+0x34

clr.dll!TranslateSecurityAttributes+0xa780c
clr.dll!ClrCreateManagedInstance+0x28a5e
clr.dll!TranslateSecurityAttributes+0xa6cee
clr.dll!TranslateSecurityAttributes+0x14e95b
clr.dll!TranslateSecurityAttributes+0x192985
clr.dll!ClrCreateManagedInstance+0xa13b3
clr.dll!GetMetaDataInternalInterface+0x326f2
clr.dll!ClrCreateManagedInstance+0x2e13
KERNEL32.DLL!BaseThreadInitThunk+0x22
ntdll.dll!RtlUserThreadStart+0x34

닷넷 프로파일러를 빼면 "ClrCreateManagedInstance" 메서드의 호출 발생이 현저하게 줄어듭니다. ClrCreateManagedInstance는 현재 deprecated 상태로 비-관리 코드에서 관리 코드를 호출할 때 사용하는 API입니다.

ClrCreateManagedInstance Function
; https://docs.microsoft.com/en-us/dotnet/framework/unmanaged-api/hosting/clrcreatemanagedinstance-function

어쨌든 여기까지의 정보로는 뭔가 부족하군요. ^^




좀 더 자세한 정보가 필요하면 역시나 덤프뿐이 없습니다. 큐잉 현상이 나타나는 순간에 풀 덤프를 뜬 후 ClrCreateManagedInstance가 발생하는 스레드의 (sos를 이용한) 콜 스택을 확인했습니다.

0:012> !clrstack
OS Thread Id: 0x18bc (12)
Unable to walk the managed stack. The current thread is likely not a 
managed thread. You can run !threads to get a list of managed threads in
the process
Failed to start stack walk: 80070057

오호~~~ 해당 스레드가 ASP.NET 요청을 처리하는 스레드가 아니었군요. 그렇다면 네이티브 콜스택을 확인해 볼까요?

0:012> k
Child-SP          RetAddr           Call Site
00000043`a0d1f9d8 00007ff8`69219fb6 clr!CallbackShimElementPcData<&CMicrodomManifestWalker::Handler_assembly_description_pcdata>
00000043`a0d1f9e0 00007ff8`69282f8e clr!Object::GetGCSafeTypeHandleIfPossible+0x7a
00000043`a0d1fa20 00007ff8`6927a110 clr!SafeGetClassIDFromObject+0xe
00000043`a0d1fa50 00007ff8`692be145 clr!AllocByClassHelper+0x6d
00000043`a0d1faa0 00007ff8`68f7fb67 clr!SVR::gc_heap::walk_heap+0xb5
00000043`a0d1faf0 00007ff8`68e45882 clr!SVR::gc_heap::garbage_collect+0x4e5
00000043`a0d1fb80 00007ff8`68ee15c7 clr!SVR::gc_heap::gc_thread_function+0xdb
00000043`a0d1fbb0 00007ff8`70e113d2 clr!SVR::gc_heap::gc_thread_stub+0x94
00000043`a0d1fcf0 00007ff8`737a5454 kernel32!BaseThreadInitThunk+0x22
00000043`a0d1fd20 00000000`00000000 ntdll!RtlUserThreadStart+0x34

(덤프 뜨는 순간이 하필 달라서였을 수도 있지만) Process Explorer에서의 콜스택과 다른 것이 흥미롭습니다. 하지만 결정적으로, 문제가 되던 그 스레드는 바로 GC 스레드였던 것입니다. 여기까지 생각하니 감이 오는 것이 있었습니다. 바로 .NET Profiler에서 원하는 콜백을 받기 위해 설정하는 옵션 중에 GC 관련한 것이 있었다는 점입니다.

COR_PRF_MONITOR
; https://docs.microsoft.com/en-us/dotnet/framework/unmanaged-api/profiling/cor-prf-monitor-enumeration

COR_PRF_MONITOR 열거 값에서 GarbageCollectionStarted, GarbageCollectionFinished, FinalizeableObjectQueued 콜백이 필요해서 COR_PRF_MONITOR_GC를 걸었었는데요. 사실, COR_PRF_MONITOR_GC 열거 값을 설정하면 다음의 콜백들도 함께 발생합니다.

  • MovedReferences
  • MovedReferences2
  • SurvivingReferences
  • SurvivingReferences2
  • ObjectReferences
  • ObjectsAllocatedByClass
  • RootReferences
  • RootReferences2
  • HandleCreated
  • HandleDestroyed

재미있는 것은, 제가 저 메서드들의 콜백에 대해 E_NOTIMPL을 반환값으로 했기 때문에 한번 호출된 이후로는 더 이상 안 불릴 거라고 가정했다는 점입니다.

STDMETHOD(MovedReferences2)(ULONG cMovedObjectIDRanges, ObjectID oldObjectIDRangeStart[], ObjectID newObjectIDRangeStart[], SIZE_T cObjectIDRangeLength[])
{
    UNREFERENCED_PARAMETER(cObjectIDRangeLength);
    return E_NOTIMPL;
}

그런데... E_NOTIMPL 반환값에 상관없이 필요할 때마다 매번 불렸습니다. ^^; 이 점이 상황을 악화시켰는데요, 가령 MovedReferences2 같은 경우에는, GC 발생 시 살아남은 객체 중 이동이 있으면 매번 발생하는 것이기 때문에 이런 것들이 합쳐져 은근히 부하를 주었던 것입니다. (하지만... 그래도 이상하긴 합니다. 아무리 콜백이 불려지는 것이지만 단순히 return 코드만 있는 것 뿐인데!)

정리해 보면, (디버깅 목적으로 제외하고) 실제 운영될 서버에 COR_PRF_MONITOR_GC 옵션이 붙은 닷넷 프로파일러를 넣는 것은 사용자 응답 시간이 길어진다는 단점으로 인해 사용해서는 안됩니다.




[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]

[연관 글]






[최초 등록일: ]
[최종 수정일: 7/10/2021]

Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
by SeongTae Jeong, mailto:techsharer at outlook.com

비밀번호

댓글 작성자
 




... 136  137  138  139  140  141  142  143  144  [145]  146  147  148  149  150  ...
NoWriterDateCnt.TitleFile(s)
1429정성태3/29/201323297개발 환경 구성: 188. SCOM 2012 - ASP.NET 모니터링 방법
1428정성태3/29/201324160개발 환경 구성: 187. SCOM 2012 환경 구성 - Management Packs
1427정성태3/29/201321234오류 유형: 171. SCOM 2012 - 원격 에이전트 설치 오류
1426정성태3/29/201324095개발 환경 구성: 186. SCOM 2012 환경 구성 - 관리 대상 추가
1424정성태3/21/201325923개발 환경 구성: 185. System Center 2012 Operations Manager 설치
1423정성태3/18/201320916오류 유형: 170. The specified domain either does not exist or could not be contacted.
1422정성태3/14/201323073오류 유형: 169. Windows 8/2012에 .NET 3.5가 설치되지 않는 경우
1421정성태3/13/201340341.NET Framework: 364. WCF RIA 서비스 + Silverlight 사용 예제
1420정성태3/12/201325063오류 유형: 168. ORA-12514: TNS:listener does not currently know of service requested in connect descriptor
1419정성태3/12/201321552Windows: 70. 관리 도구에서 "Windows Server Backup" 항목이 없는 경우
1418정성태2/28/201331462오류 유형: 167. Internet Explorer 10 설치 후 Flash 객체의 메서드/속성 접근 오류가 발생한다면?
1417정성태2/25/201327603.NET Framework: 363. ASP.NET AJAX PageMethods - ASPX.cs의 static 메서드를 AJAX로 호출파일 다운로드1
1416정성태2/22/201330208개발 환경 구성: 184. Xamarin 2.0 - Visual Studio에서 Android 앱을 폰으로 직접 배포하는 방법
1415정성태2/21/201337553개발 환경 구성: 183. Xamarin 2.0 - 윈도우 환경의 Visual Studio에서 C#으로 iOS/Android 응용 프로그램 개발 [4]파일 다운로드1
1414정성태2/21/201332706개발 환경 구성: 182. JMeter로 XML 웹 서비스 호출에 대한 부하 테스트 방법파일 다운로드2
1413정성태2/19/201332057VC++: 66. Chromium 컴파일하는 방법 - 두 번째 이야기 [3]
1412정성태2/6/201333917VC++: 65. Python 소스코드를 Visual C++로 빌드하는 방법 [3]
1411정성태1/31/201349263개발 환경 구성: 181. 무료 데이터베이스 서버 성능 비교(SQL Server Express, IBM DB2 Express, MySQL, Sybase, PostgreSQL, Oracle XE) [9]
1410정성태1/31/201331079.NET Framework: 362. C# - 닷넷 응용 프로그램에서 Sybase DB 사용 [1]파일 다운로드1
1409정성태1/30/201335013.NET Framework: 361. C# - 공유기 관리 웹 페이지 인증 [4]파일 다운로드1
1408정성태1/29/201329846.NET Framework: 360. C# - 닷넷 응용 프로그램에서 DB2 Express-C 데이터베이스 사용 (2) [1]파일 다운로드1
1407정성태1/29/201328245.NET Framework: 359. C# - 닷넷 응용 프로그램에서 DB2 Express-C 데이터베이스 사용 (1)
1406정성태1/22/201322633개발 환경 구성: 180. Windows Server 2012 RC 버전을 RTM으로 업그레이드하는 방법
1405정성태1/16/201344287.NET Framework: 358. C# - 닷넷 응용 프로그램에서 MySQL(MySqlConnector) 사용 [7]파일 다운로드1
1404정성태1/15/201329140개발 환경 구성: 179. Hyper-V VM 복사는 robocopy로. [2]
1403정성태1/14/201331971.NET Framework: 357. .NET 4.5의 2GB 힙 한계 극복
... 136  137  138  139  140  141  142  143  144  [145]  146  147  148  149  150  ...