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)
1353정성태9/17/201225698.NET Framework: 337. Python의 생성기와 코루틴을 C#으로 표현하면. [2]파일 다운로드1
1352정성태9/13/201223730.NET Framework: 336. .NET Profiler가 COM 개체일까?
1351정성태9/13/201228183디버깅 기술: 49. windbg - .NET Framework 스레드 개체의 COM Apartment 유형 확인하는 방법
1350정성태9/12/201228871개발 환경 구성: 167. (실은) 무료가 아니었던 AWS EC2 서비스 [4]
1349정성태9/11/201260590VS.NET IDE: 74. Visual Studio의 '새 파일'을 UTF-8 인코딩으로 지정하는 방법 [4]
1348정성태9/11/201228047오류 유형: 164. Active Directory - Functional Level 승격이 안 되는 문제
1347정성태9/10/201230459Windows: 62. 윈도우 서버 2012 - Hyper-V 서버 마이그레이션 [1]
1346정성태9/10/201231334Windows: 61. 윈도우 서버 2012 - Active Directory 서버 마이그레이션
1345정성태9/10/201235355스크립트: 12. 파이썬 - Win32 DLL 연동 [2]
1344정성태9/10/201228509오류 유형: 163. .NET Framework 4.5 제거 후 Visual Studio 2010 실행 시 Unknown Error
1343정성태9/8/201242305스크립트: 11. 파이썬(Python) 윈도우 개발 환경 [7]
1342정성태9/6/201226455VS.NET IDE: 73. Visual Studio 2012 - XmlCodeGenerator 마이그레이션
1341정성태9/4/201235791Windows: 60. Hyper-V에서 RemoteFX 없이 DirectX 11 제공 [12]
1340정성태9/4/201227971개발 환경 구성: 166. DOS - ping 결과에서 평균 응답 시간값 추출하기 [3]
1339정성태9/4/201230417개발 환경 구성: 165. 새로운 Visual Studio 2012 원격 디버깅 툴 [5]
1338정성태9/4/201232207.NET Framework: 335. C# - (핸들을 이용하여) 모든 열린 파일을 열람 [6]파일 다운로드1
1337정성태8/30/201222016Phone: 7. 디버거로 실습해 보는 윈도우 폰의 Tombstone 상태파일 다운로드1
1336정성태8/30/201240061.NET Framework: 334. 스레드 비정상 종료로 발생하는 CLOSE_WAIT 소켓 상태 [2]파일 다운로드1
1335정성태8/30/201228815Windows: 59. Hyper-V Internal 네트워크 VM의 인터넷 접속
1334정성태8/29/201248099.NET Framework: 333. 코드로 재현하는 소켓 상태(FIN_WAIT1, FIN_WAIT2, TIME_WAIT, CLOSE_WAIT, LAST_WAIT) [6]
1333정성태8/27/201251522개발 환경 구성: 164. system32 폴더에 있는 파일의 권한 조정 [2]
1332정성태8/23/201223434Team Foundation Server: 48. TFS - Team Project Collection 이전하는 방법
1331정성태8/23/201226591오류 유형: 162. Database '...' already exists. Choose a different database name. (Microsoft SQL Server, Error: 1801)
1330정성태8/22/201227348Team Foundation Server: 47. 5인 이내의 팀, 또는 개인 로컬 소스 관리를 위한 무료 TFS Express
1329정성태8/21/201222804오류 유형: 161. Azure - Storage 삭제가 안되는 경우 [1]
1328정성태8/20/201233217개발 환경 구성: 163. IIS 7 - "MIME Types" 설정 아이콘이 없는 경우
... 136  137  138  139  140  141  142  143  144  145  146  147  [148]  149  150  ...