Ваша проблема не вызвана утечкой управляемого памяти. Ясно, что вы щекочут ошибку где-то в неуправляемом коде.
Метод SyncFlush() вызывается после нескольких вызовов MILCore и, как представляется, вызывает немедленную обработку изменений, которые были отправлены, вместо того, чтобы оставаться в очереди для последующей обработки. Поскольку вызов обрабатывает все ранее отправленные, ничто в вашем визуальном дереве не может быть исключено из стека вызовов, который вы отправили.
Стек вызовов, включающий неуправляемые вызовы, может оказаться более полезной информацией. Запустите приложение под VS.NET с собственной отладкой или с помощью windbg или другого отладчика собственного кода. Установите отладчик для прерывания исключения и получите стек вызовов в относительной точке останова.
Стек вызовов, конечно, спускается в MILCore, и оттуда он может перейти в уровень DirectX и драйвер DirectX. Вопрос о том, какая часть вашего кода вызвала проблему, может быть найден где-то в этом наборе вызовов.
Скорее всего, MILCore передает огромное значение некоторого параметра в DirectX на основе того, что вы ему рассказываете. Проверьте приложение на все, что может вызвать ошибку, которая заставит DirectX выделять много памяти. Примерами вещей для поиска могут быть:
- Bitmap Источники, которые настроены на загрузку с очень высоким разрешением.
- Большие WritableBitmaps
- Очень большой (или отрицательный) преобразование или размер ценности
Другой способ атаковать эту проблему постепенно упрощать приложения, пока проблема не исчезнет, то выглядит очень closedly на то, что вы удалили последний , Когда это удобно, это может быть полезно сделать в виде бинарного поиска: сначала вырезать половину визуальной сложности. Если он работает, верните половину того, что было удалено, иначе удалите еще одну половину. Повторяйте до конца.
Также обратите внимание, что на самом деле удалить компоненты пользовательского интерфейса, чтобы MILCore не видел. Любой Visual с Visibility.Hidden может быть пропущен полностью.
Существует не обобщенный способ избежать этой проблемы, но метод поиска поможет вам определить, что конкретно нужно изменить, чтобы исправить его в конкретном случае.
В стеке вызовов можно сказать, что вы обнаружили ошибку в .NET Framework или драйверах DirectX для конкретной видеокарты.
Что касается второго трассировки стеки вы публикуемой
Джона Knoeller является правильным, что переход от RtlFreeHeap к ConvertToUnicode нонсенс, но рисует неправильный вывод из него. Мы видим, что ваш отладчик потерялся при отслеживании стека. Он начал корректно из исключения, но потерялся ниже фрейма Assembly.ExecuteMainMethod
, потому что эта часть стека была перезаписана, когда обработано исключение, и был вызван отладчик.
К сожалению, любой анализ этой трассировки стека бесполезен для ваших целей, потому что он был захвачен слишком поздно. То, что мы видим, является исключением, возникающим при обработке WM_LBUTTONDOWN, которая преобразуется в WM_SYSCOMMAND, которая затем выдает исключение. Другими словами, вы нажали на то, что вызвало системную команду (например, изменение размера), что вызвало исключение. В момент, когда эта трассировка стека была захвачена, исключение уже обрабатывалось. Причина, по которой вы видите вызовы User32 и UxTheme, заключается в том, что они связаны с обработкой нажатия кнопки. Они не имеют ничего общего с реальной проблемой.
Вы находитесь на правильном пути, но вам нужно будет захватить трассировку стека в момент сбоя распределения (или вы можете использовать один из других подходов, которые я предложил выше).
Вы узнаете, что у вас есть правильная трассировка стека, когда все управляемые кадры в вашей первой трассировке стека появляются в ней, а верхняя часть стека является сбоем в распределении памяти. Обратите внимание, что нас действительно интересуют только неуправляемые кадры, которые появляются над вызовом DUCE+Channel.SyncFlush
- все, что ниже, будет .NET Framework и вашим кодом приложения.
Как получить родной трассировки стека в нужное время
Вы хотите получить трассировку стека во время первой ошибки распределения памяти в пределах DUCE+Channel.SyncFlush
вызова показано на рисунке. Это может быть сложно. Есть три подхода, которые я использую: (обратите внимание, что в каждом случае при запуске с точкой останова внутри вызова SyncFlush - смотрите примечание ниже для более подробной информации)
Установите отладчик ломаться на все исключения (управляемый и неуправляемый) , затем продолжайте движение (F5 или «g») до тех пор, пока он не разрывается на выделение выделения памяти, которое вас интересует.Это первое, что нужно попробовать, потому что оно быстро, но часто не работает при работе с собственным кодом, потому что собственный код часто возвращает код ошибки в вызывающий собственный код вместо того, чтобы бросать исключение.
Установите отладчик, чтобы разбить все исключения, а также установить точки останова в общих подпрограммах распределения памяти, а затем повторно нажать F5 (перейти) до тех пор, пока не произойдет исключение, подсчитав, сколько F5s вы нажмете. В следующий раз, когда вы запустите, используйте еще одно F5, и вы можете быть в вызове выделения, который сгенерировал исключение. Захватите стек вызовов в Блокнот, затем F10 (шаг за шагом) оттуда, чтобы увидеть, действительно ли это было неудачное распределение.
Установите точку останова на первом собственном фрейме, который называется SyncFlush (это wpfgfx_v0300! MilComposition_SyncFlush), чтобы пропустить переход с управляемого нативный, а затем F5 для запуска. F10 (перейдите) через функцию до EAX содержит один из кодов ошибок E_OUTOFMEMORY (0x8007000E), ERROR_OUTOFMEMORY (0x0000000E) или ERROR_NOT_ENOUGH_MEMORY (0x0000008). Обратите внимание на самую последнюю инструкцию «Вызов». В следующий раз, когда вы запустите программу, бегите туда и входите в нее. Повторяйте это до тех пор, пока вы не перейдете к вызову выделения памяти, вызвавшему проблему, и дамп трассировки стека. Обратите внимание, что во многих случаях вы столкнетесь с довольно сложной структурой данных, поэтому необходим определенный интеллект, чтобы установить соответствующую точку останова, чтобы пропустить цикл, чтобы вы могли быстро добраться туда, где нужно. Этот метод очень надежный, но очень трудоемкий.
Примечание: В каждом случае вы не хотите, чтобы установить точки останова или начать пошаговом пока приложение не находится внутри неисправного DUCE+Channel.SyncFlush
вызова. Чтобы обеспечить это, запустите приложение, когда все точки останова отключены. Когда он запущен, включите точку останова на System.Windows.Media.Composition.DUCE+Channel.SyncFlush
и измените размер окна. В первый раз просто нажмите F5, чтобы исключить ошибку при первом вызове SyncFlush (если нет, подсчитайте, сколько раз вам нужно ударить F5 до возникновения исключения). Затем отключите точку останова и перезапустите программу. Повторите эту процедуру, но на этот раз после того, как вы нажмете вызов SyncFlush в нужное время, установите контрольные точки или выполните однократное нажатие, как описано выше.
Рекомендация
Методики отладки, которые я описываю выше трудоемко: План потратить несколько часов, по крайней мере. Из-за этого я обычно многократно пытаюсь упростить свое приложение, чтобы узнать, что именно щекочет ошибку перед тем, как перейти в отладчик для чего-то вроде этого. Это имеет два преимущества: он даст вам хороший репрограмм для отправки поставщику видеокарты, и он сделает вашу отладку быстрее, потому что будет меньше отображаться и, следовательно, меньше кода для однократного прохождения, меньше распределений и т. Д.
Поскольку проблема возникает только с конкретной видеокартой, нет сомнений в том, что проблема заключается либо в ошибке в драйвере графической карты, либо в коде MilCore, который ее вызывает. Скорее всего, это драйвер видеокарты, но возможно, что MilCore передает недопустимые значения, которые обрабатываются на большинстве графических карт, но не в этом. Методы отладки, описанные выше, скажут вам следующее: например, если MilCore сообщает графической карте о распределении области 1000000x1000000 пикселей, а графическая карта дает правильную информацию о разрешении, ошибка находится в MilCore. Но если запросы MilCore разумны, ошибка возникает в драйвере графической карты.
Спасибо за вашу помощь и анализ. Спасибо Рэй Бернс, Джон Кнуллер, Крис Никол и все посетители. – whunmr
whunmr, вы когда-нибудь могли найти основную причину проблемы? Если да, можете ли вы поделиться своими выводами? – Charlie
Привет, Чарли, я не думаю, что нашел истинную причину этой проблемы. И это уже давно. – whunmr