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

비밀번호

댓글 작성자
 




... 106  107  108  109  110  111  112  [113]  114  115  116  117  118  119  120  ...
NoWriterDateCnt.TitleFile(s)
11099정성태11/7/201630609.NET Framework: 620. C#에서 C/C++ 함수로 콜백 함수를 전달하는 예제 코드파일 다운로드1
11098정성태11/7/201619925오류 유형: 368. 빌드 이벤트에서 robocopy 사용 시 $(TargetDir) 매크로를 지정하는 경우 오류 발생
11097정성태11/7/201622860오류 유형: 367. go install: no install location for directory [...경로...] outside GOPATH
11096정성태11/6/201626671디버깅 기술: 83. PDB 파일을 수동으로 다운로드하는 방법
11095정성태11/6/201622913.NET Framework: 619. C# - Cognitive Services 중의 하나인 Face API를 사용해 얼굴 인식 및 흐림(blur) 효과 적용 [1]파일 다운로드1
11094정성태11/5/201624586VC++: 105. Visual Studio 2013/2015 - Ceemple OpenCV 확장을 이용한 웹캠 영상 출력
11093정성태11/4/201624475웹: 34. Edge 브라우저도 지원하는 클립보드 복사를 위한 자바스크립트 코드
11092정성태11/3/201631446.NET Framework: 618. C# - NAudio를 이용한 MP3 파일 재생 [5]파일 다운로드1
11091정성태11/3/201626264VC++: 104. std::call_once를 이용해 thread-safe한 Singleton 객체 생성파일 다운로드1
11090정성태11/1/201627699VC++: 103. C++ CreateTimerQueue, CreateTimerQueueTimer 예제 코드 [9]파일 다운로드1
11089정성태11/1/201626488디버깅 기술: 82. Windows 10을 위한 Symbol(PDB) 파일 내려받는 방법 [2]
11088정성태11/1/201630662.NET Framework: 617. C# - AForge.NET을 이용한 MP4 동영상 파일 재생 [7]파일 다운로드1
11087정성태11/1/201625032.NET Framework: 616. AForge.Video.FFMPEG를 최신 버전의 ffmpeg 파일로 의존성을 변경하는 방법파일 다운로드1
11086정성태11/1/201618894오류 유형: 366. The Microsoft Passport Container service terminated with the following error: General access denied error
11085정성태10/27/201633246.NET Framework: 615. C# - AForge.NET을 이용한 웹캠 영상 출력 [2]파일 다운로드1
11084정성태10/26/201621336오류 유형: 365. The User Profile Service service failed to the sign-in.
11083정성태10/26/201627817Windows: 131. 윈도우 10에서 사라진 "Adapters and Bindings" 네트워크 우선 순위 조정 기능 [1]
11082정성태10/26/201629706.NET Framework: 614. C# - DateTime.Ticks의 정밀도 [4]파일 다운로드1
11081정성태10/26/201620262오류 유형: 364. You need to fix your Microsoft Account for apps on your other devices to be able to launch apps and continue experiences on this device.
11080정성태10/24/201623365Windows: 130. Windows Server 2016 Nano 서버 설치 방법
11079정성태10/21/201620504Windows: 129. Windows Server 2016 설치 CD에 있는 Convert-WindowsImage.ps1 사용 방법 정리
11078정성태10/21/201621847Windows: 128. Windows Server 2016 Nano 서버 VHD 이미지 만드는 방법 - TP5 기준
11077정성태10/21/201620355오류 유형: 363. Active Directory 서버의 NETLOGON 서비스가 멈췄을 때 발생하는 문제
11076정성태10/21/201619887오류 유형: 362. 윈도우 백업 시 오류 - 0x80780040
11075정성태10/20/201620869Windows: 127. Convert-WindowsImage.ps1 사용 방법 정리
11074정성태10/20/201629141Windows: 126. Windows Server 2016 평가판을 정식 버전으로 라이선스 변경하는 방법
... 106  107  108  109  110  111  112  [113]  114  115  116  117  118  119  120  ...