2009-12-22 4 views
14

최근 응용 프로그램에 이상한 문제가 발생했습니다.WP32의 win32 창

WPF 창 크기를 조정할 때 응용 프로그램에 WPF 창에 win32 창이있는 경우 때 문제가 발생했습니다.

스택 트레이스 : 또한

Exception object: 0000000002ab2c78 
Exception type: System.OutOfMemoryException 
InnerException: <none> 
StackTrace (generated): 
    SP  IP  Function 
    0048D94C 689FB82F PresentationCore_ni!System.Windows.Media.Composition.DUCE+Channel.SyncFlush()+0x80323f 
    0048D98C 681FEE37 PresentationCore_ni!System.Windows.Media.Composition.DUCE+CompositionTarget.UpdateWindowSettings(ResourceHandle, RECT, System.Windows.Media.Color, Single, System.Windows.Media.Composition.MILWindowLayerType, System.Windows.Media.Composition.MILTransparencyFlags, Boolean, Boolean, Boolean, Int32, Channel)+0x127 
    0048DA38 681FEAD1 PresentationCore_ni!System.Windows.Interop.HwndTarget.UpdateWindowSettings(Boolean, System.Nullable`1<ChannelSet>)+0x301 
    0048DBC8 6820718F PresentationCore_ni!System.Windows.Interop.HwndTarget.UpdateWindowSettings(Boolean)+0x2f 
    0048DBDC 68207085 PresentationCore_ni!System.Windows.Interop.HwndTarget.UpdateWindowPos(IntPtr)+0x185 
    0048DC34 681FFE9F PresentationCore_ni!System.Windows.Interop.HwndTarget.HandleMessage(Int32, IntPtr, IntPtr)+0xff 
    0048DC64 681FD0BA PresentationCore_ni!System.Windows.Interop.HwndSource.HwndTargetFilterMessage(IntPtr, Int32, IntPtr, IntPtr, Boolean ByRef)+0x3a 
    0048DC88 68C6668E WindowsBase_ni!MS.Win32.HwndWrapper.WndProc(IntPtr, Int32, IntPtr, IntPtr, Boolean ByRef)+0xbe 
    0048DCD4 68C665BA WindowsBase_ni!MS.Win32.HwndSubclass.DispatcherCallbackOperation(System.Object)+0x7a 
    0048DCE4 68C664AA WindowsBase_ni!System.Windows.Threading.ExceptionWrapper.InternalRealCall(System.Delegate, System.Object, Boolean)+0x8a 
    0048DD08 68C6639A WindowsBase_ni!System.Windows.Threading.ExceptionWrapper.TryCatchWhen(System.Object, System.Delegate, System.Object, Boolean, System.Delegate)+0x4a 
    0048DD50 68C64504 WindowsBase_ni!System.Windows.Threading.Dispatcher.WrappedInvoke(System.Delegate, System.Object, Boolean, System.Delegate)+0x44 
    0048DD70 68C63661 WindowsBase_ni!System.Windows.Threading.Dispatcher.InvokeImpl(System.Windows.Threading.DispatcherPriority, System.TimeSpan, System.Delegate, System.Object, Boolean)+0x91 
    0048DDB4 68C635B0 WindowsBase_ni!System.Windows.Threading.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority, System.Delegate, System.Object)+0x40 
    0048DDD8 68C65CFC WindowsBase_ni!MS.Win32.HwndSubclass.SubclassWndProc(IntPtr, Int32, IntPtr, IntPtr)+0xdc 

StackTraceString: <none> 
HResult: 8007000e 

, 내가 찾은 몇 가지 관련 링크 :

relatedA

relatedB

  1. 피하거나이 프로를 처리 할 수있는 방법이 있나요 흠?

  2. 실제 문제를 찾는 방법은 무엇입니까?

  3. 호출 스택에서 문제가 .NET Framework에서 발생했는지 확인할 수 있습니까?

답변 해 주셔서 감사합니다.

+0

귀하의 도움과 분석에 감사드립니다. Ray Burns, John Knoeller, Chris Nicol 및 모든 방문객에게 감사드립니다. – whunmr

+0

whunmr, 혹시 문제의 근본 원인을 찾을 수 있었습니까? 그렇다면 결과를 공유 할 수 있습니까? – Charlie

+0

안녕하세요. 찰리,이 문제의 진정한 원인을 찾지 못했을 것 같습니다. 그리고 그것은 오래전 일입니다. – whunmr

답변

21

귀하의 문제는 관리되는 메모리 누수가 발생하지 않습니다. 분명히 비 관리 코드의 어딘가에서 버그를 간질입니다.

여러 MILCore 호출 후에 SyncFlush() 메서드가 호출되며 변경 내용을 나중에 처리하기 위해 대기열에 두지 않고 즉시 처리하도록 나타납니다. 호출은 이전에 전송 된 모든 것을 처리하므로 시각적 트리의 아무 것도 전송 한 호출 스택에서 제외 될 수 있습니다.

관리되지 않는 호출을 포함하는 호출 스택이 더 유용한 정보를 나타낼 수 있습니다. VS.NET에서 기본 디버깅을 사용하거나 windbg 또는 다른 원시 코드 디버거를 사용하여 응용 프로그램을 실행합니다. 디버거가 예외를 중단하도록 설정하고 상대 중단 점에서 호출 스택을 가져옵니다.

호출 스택은 물론 MILCore로 내려 가고 거기에서 DirectX 레이어와 DirectX 드라이버로 들어갈 수 있습니다. 코드의 어느 부분에서 문제가 발생했는지에 대한 단서가이 기본 호출 스택의 어딘가에있을 수 있습니다.

MILCore가 말하는 내용에 따라 MILCore가 DirectX에 큰 매개 변수 값을 전달할 가능성이 있습니다. 응용 프로그램에서 DirectX가 많은 메모리를 할당하게하는 버그를 유발할 수있는 사항이 있는지 확인하십시오. 찾을 내용의 예는 다음과 같습니다.

  • 매우 높은 해상도로로드되도록 설정된 비트 맵 소스.
  • 대형 WritableBitmaps
  • 가 매우 큰 (또는 음) 변환 또는 크기이 문제가 문제가 사라질 때까지 점진적 다음, 응용 프로그램을 단순화 마지막으로 제거 무엇 매우 closedly 보는 것입니다 공격

또 다른 방법 값 . 편리 할 때, 이진 검색으로 이것을 수행하는 것이 좋습니다. 처음에는 시각적 복잡도의 절반을 잘라냅니다. 작동하는 경우 제거한 부분의 절반을 다시 넣고, 그렇지 않으면 다른 부분을 제거하십시오. 완료 될 때까지 반복하십시오.

실제로 MILCore가 보지 못하도록 UI 구성 요소를 실제로 제거하는 것은 불필요합니다. Visibility.Hidden이있는 모든 비주얼은 완전히 건너 뛸 수 있습니다.

이 문제를 방지 할 일반화 된 방법이 없지만, 검색 기술은 특별히 특별한 경우에 그것을 해결하기 위해 변경해야하는 무엇을 정확하게 파악하는 데 도움이됩니다.

당신이 NET 프레임 워크 또는 특정 비디오 카드의 다이렉트 X 드라이버 중 하나에서 버그를 발견 한 것으로, 호출 스택에서 말을하는 것이 안전합니다. 당신이

존 Knoeller을 게시 두 번째 스택 추적에 관한

ConvertToUnicode에 RtlFreeHeap의 전환이 말도 있지만, 그것에서 잘못된 결론을 그리는 것이 올바른 것입니다. 우리가보고있는 것은 스택을 추적 할 때 디버거가 손실되었다는 것입니다. 예외에서 올바르게 시작되었지만 Assembly.ExecuteMainMethod 프레임 아래에서 손실되었습니다. 예외가 처리되고 디버거가 호출 될 때 스택의 일부가 덮어 써 졌기 때문입니다.

불행히도이 스택 추적에 대한 분석은 너무 늦게 캡처 되었기 때문에 목적에 쓸모가 없습니다. 우리가보고있는 것은 예외를 잡는 WM_SYSCOMMAND로 변환되는 WM_LBUTTONDOWN을 처리하는 동안 예외가 발생한다는 것입니다. 즉, 시스템 명령 (예 : 크기 조정)을 유발 한 항목을 클릭하여 예외가 발생했습니다. 이 스택 추적이 캡처 된 시점에서 이미 예외가 처리되고있었습니다. User32 및 UxTheme 호출이 표시되는 이유는 단추 클릭 처리와 관련되어 있기 때문입니다. 그들은 진짜 문제와 관련이 없습니다.

는 당신이 바로 그 궤도에,하지만 당신은 할당이 실패 순간에 스택 트레이스를 캡처해야합니다 (또는 내가 위에서 제시 한 다른 방법 중 하나를 사용할 수 있습니다).

당신은 첫 번째 스택 트레이스의 모든 관리 프레임이 나타납니다 스택의 상단이 실패한 메모리 할당 때 올바른 스택 추적을 알 수 있습니다. DUCE+Channel.SyncFlush 호출 위에 나타나는 관리되지 않는 프레임에만 관심이 있습니다. NET Framework와 응용 프로그램 코드는 모두 아래에 있습니다. 적절한 시간 당신은 시간에 표시된 DUCE+Channel.SyncFlush 호출 내에서 첫 번째 메모리 할당 실패를 스택 트레이스를 취득 할

에서 네이티브 스택 추적을하는 방법을

. 이것은 까다로울 수 있습니다. 내가 사용하는 세 가지 방법이 있습니다 : (당신이 SyncFlush 호출 내부에 중단 점으로 시작 각각의 경우에 있습니다 - 자세한 내용은 아래 참고 참조)

  1. 는 (관리와 관리되지 않는) 모든 예외에 휴식 디버거 설정 , 관심이있는 메모리 할당 예외가 발생할 때까지 계속 이동 (F5 또는 "g")하십시오.이것은 빠른 것이기 때문에 가장 먼저 시도하지만, 네이티브 코드가 종종 예외를 던지기보다는 호출하는 네이티브 코드에 오류 코드를 반환하기 때문에 네이티브 코드로 작업 할 때 종종 실패합니다.

  2. 모든 예외를 중단하고 공통 메모리 할당 루틴에 중단 점을 설정 한 다음 예외가 발생할 때까지 반복적으로 F5 (이동) 키를 눌러 충돌 한 F5의 수를 계산합니다. 다음 번에 실행할 때 F5를 적게 사용하면 예외를 생성 한 할당 호출이있을 수 있습니다. 호출 스택을 메모장에 캡쳐 한 다음 거기에서 반복해서 F10 (단계를 건너 뛰기)을 반복하여 실제로 실패한 할당인지 확인합니다.

  3. SyncFlush (this는 wpfgfx_v0300! MilComposition_SyncFlush)가 호출 한 첫 번째 네이티브 프레임에 중단 점을 설정하여 관리되는 네이티브 변환을 건너 뛰고 F5를 실행합니다. EAX가 오류 코드 E_OUTOFMEMORY (0x8007000E), ERROR_OUTOFMEMORY (0x0000000E) 또는 ERROR_NOT_ENOUGH_MEMORY (0x0000008) 중 하나를 포함 할 때까지 함수를 통해 F10을 단계적으로 수행하십시오. 가장 최근의 "호출"명령에 유의하십시오. 다음에 프로그램을 실행하면 거기로 가서 실행하십시오. 문제를 일으킨 메모리 할당 호출이 나올 때까지이 작업을 반복하고 스택 추적을 덤프하십시오. 대부분의 경우 큰 데이터 구조를 반복적으로 반복하므로 루프를 건너 뛰고 적절한 중단 점을 설정해야하므로 신속하게 수행해야하는 위치를 얻을 수 있습니다. 이 기술은 매우 신뢰할 만하지만 매우 노동 집약적입니다.

참고 : 각각의 경우에 당신은 중단 점을 설정하거나 응용 프로그램이 실패 DUCE+Channel.SyncFlush 호출 내부까지 단계별 실행을 시작하고 싶지 않습니다. 이를 보장하려면 모든 중단 점이 비활성화 된 상태에서 응용 프로그램을 시작하십시오. 실행 중일 때 System.Windows.Media.Composition.DUCE+Channel.SyncFlush에서 중단 점을 활성화하고 창 크기를 조정하십시오. 처음에는 F5를 눌러서 첫 번째 SyncFlush 호출에서 예외가 실패하는지 확인합니다 (그렇지 않은 경우 예외가 발생하기 전에 F5를 몇 번이나 눌려야하는지 계산합니다). 그런 다음 중단 점을 비활성화하고 프로그램을 다시 시작하십시오. 이 절차를 반복하되 이번에는 SyncFlush 호출을 적시에 실행하거나 중단 점을 설정하거나 위에서 설명한대로 단일 단계 실행을 수행하십시오. 적어도 몇 시간을 보낼 계획 :

권장

제가 위에서 설명하는 디버깅 기술은 노동 집약적이다. 이 때문에 일반적으로 내 응용 프로그램을 반복적으로 단순화하여 디버거에 점프하기 전에 버그를 간지럽히는 것을 정확히 찾으려고합니다. 이 두 가지 장점이 있습니다 : 그것은 당신에게 그래픽 카드 공급 업체에 보낼 수있는 좋은 생식을 줄 것이며, 더 빨리 더 적은이 표시되기 때문에 디버깅을 할 것이며 통해 한 단계 더 적은 할당 등을하는 것이 적은 코드

특정 그래픽 카드에서만 문제가 발생하기 때문에 문제가 그래픽 카드 드라이버의 버그인지 또는이를 호출하는 MilCore 코드인지 의심의 여지가 없습니다. 대부분 그래픽 카드 드라이버에있을 가능성이 있지만, MilCore가 대부분의 그래픽 카드가 올바르게 처리하지만이 것은 아닌 잘못된 값을 전달할 가능성이 있습니다. 앞에서 설명한 디버깅 기술을 통해 알 수 있습니다. 예를 들어, MilCore가 그래픽 카드에 1000000x1000000 픽셀 영역을 할당한다고 알리고 그래픽 카드가 올바른 해상도 정보를 제공하면 버그는 MilCore에 있습니다. 그러나 MilCore의 요청이 합리적이라면 버그는 그래픽 카드 드라이버에 있습니다.

+1

감사합니다. 안녕하세요, 관리되는 스택과 관리되지 않는 스택을 덤프했습니다. "uxtheme! _ThemeDefWindowProc"의 문제가 있다고 할 수 있습니까? – whunmr

+1

아니요, UxTheme과 관련이 없습니다. UxTheme 코드는 버튼 클릭 만 처리합니다. 스택 추적은 올바른 종류의 추적이지만 올바른 시간에 수행되지는 않습니다. 내 대답에 대한 설명과 좋은 스택 추적을위한 몇 가지 팁을 추가했습니다. 희망 그들은 도움이됩니다. –

2

여기 WPF의 메모리 누수에 대해 유용한 article이 있습니다. 또한 RedGate의 ANTS Performance 및/또는 Memory Profiler와 같은 것을 고려하여 이런 문제를 진단하는 데 도움이 될 수 있습니다.

HTH는

+0

예 ... 개미 메모리 프로파일 러는 나를위한 최상의 옵션처럼 보입니다. – Anvaka

1

스택 부분 (또는 적어도 UXTheme 항목)이 신뢰할 만한지 잘 모르겠습니다. 스택 하단이 정상적으로 보입니다. 그리고 우리는 클린업을 시도하는 예외 처리자 인 것처럼 보입니다. 그런 다음 다양한 계층의 힙 관리 코드에 대한 중첩 호출이 많이 발생합니다.

그러나 RtlFreeHeap에서 ConvertToUnicode에 스택 전환은 어떤 이해가되지 않습니다이 부분.위의 모든 내용은 이전 스택 사용에서 남은 것으로 판단됩니다. RtlFreeHeap 점에서

0048f40c 6b88f208 mscorwks!_EH_epilog3_GS+0xa, calling mscorwks!__security_check_cookie 
0048f410 6b8a756e mscorwks!SString::ConvertToUnicode+0x81, calling mscorwks!_EH_epilog3_GS 
0048f424 77b4371e ntdll_77b10000!RtlpFreeHeap+0xbb1, calling ntdll_77b10000!RtlLeaveCriticalSection 
0048f42c 77b436fa ntdll_77b10000!RtlpFreeHeap+0xb7a, calling ntdll_77b10000!_SEH_epilog4 

충돌이 이 문제가 관리되지 않는 코드에 있지만 manged했던 개체에 대한 메모리가 궁극적으로 관리되지 않는 메모리에서 할당해야한다는을 제안 손상, 힙, 그래서이 될 수 있습니다.

관리되지 않는 창으로 인해 힙이 손상 될 수있는 장소를 찾으십시오. 동일한 할당의 여러 프리 또는 할당의 경계를 덮어 씁니다.

+0

분석해 주셔서 감사합니다. 이제 UXTheme이 잘 작동한다고 결론을 내릴 수 있습니다. – whunmr

+1

@John Knoeller : 예 네가 알고있는 전환은 스택 덮어 쓰기의 일부입니다. 나머지 분석은 원래 추적이 SyncFlush 내부에서 발생하고 버튼 클릭에 대한 응답으로 OutOfMemoryException이 발생한다는 사실을 제외하고 **를 제외하고는 ** 그럴듯합니다. RtlpFreeHeap 호출이'Application.Run'을 포함하여 모든 관리되는 코드의 외부에 있기 때문에,이 호출 스택은 분명히 이전 것과 같은 예외를 보여주지 못합니다. 특히 크기가 작을 때 메모리 부족 예외가 발생하는 오류를 표시하지 않습니다. –

+0

문제의 스택 덮어 쓰기는 스레드가 종료 된 것이 원인입니다. 마지막 출구에는 RtlpFreeHeap의 GP 오류가 포함되어 있다고 생각할 수 있지만 실제로 스택 추적에 표시되는 것은 없습니다. 손상 가능성이 전혀 없으며 처리되지 않은 OutOfMemoryException으로 인해 정상적인 예외 종료가 발생합니다. 그럼에도 불구하고 힙을 손상시킬 수있는 사항에 대한 관리되지 않는 코드를 확인하는 것은 이러한 경우 항상 좋은 아이디어입니다. –

0

SyncFlush 문제가있는 사용자에게 도움이 될 경우 MSDN 구독을 통해 Microsoft의 탁월한 지원으로 문제를 해결했습니다. timeBeginPeriod 및 timeEndPeriod 호출을 사용하여 해제하는 것보다 더 많은 멀티미디어 타이머를 생성하는 것으로 나타났습니다. 이러한 타이머는 제한된 리소스이며 일단 사용량이 많아지면 WPF 렌더링 스레드가 타이머를 기다리고 작업을 종료합니다.

관련 문제