Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Note
Эта статья относится к .NET Framework. Он не применяется к более новым реализациям .NET, включая .NET 6 и более поздние версии.
releaseHandleFailed Помощник по управляемой отладке (MDA) активируется для уведомления разработчиков о том, когда ReleaseHandle метод класса, производный от SafeHandle или CriticalHandle возвращаетсяfalse.
Симптомы
Утечки ресурсов или памяти. ReleaseHandle Если метод класса, производный от SafeHandle или CriticalHandle завершающегося сбоем, ресурс, инкапсулированный классом, может не быть освобожден или удален.
Причина
Пользователи должны предоставить реализацию ReleaseHandle метода, если они создают классы, производные от SafeHandle или CriticalHandle; таким образом, обстоятельства зависят от отдельного ресурса. Однако требования приведены следующим образом:
SafeHandle и CriticalHandle типы представляют оболочки вокруг жизненно важных ресурсов процесса. Утечка памяти сделает процесс непригодным для использования с течением времени.
Метод ReleaseHandle не должен выполнять свою функцию. Когда процесс получает такой ресурс, ReleaseHandle это единственный способ его освобождения. Поэтому сбой подразумевает утечку ресурсов.
Любой сбой, который происходит во время выполнения ReleaseHandleресурса, что препятствует выпуску ресурса, является ошибкой в реализации ReleaseHandle самого метода. Программист несет ответственность за выполнение контракта, даже если код вызывает код, написанный кем-то другим для выполнения своей функции.
Разрешение
Код, использующий конкретный SafeHandle (или CriticalHandle) тип, который вызвал уведомление MDA, следует проверить, искать места, где значение необработанного дескриптора извлекается из и копируется в SafeHandle другом месте. Это обычная причина сбоев в пределах SafeHandle или CriticalHandle реализации, так как использование необработанного значения дескриптора больше не отслеживается средой выполнения. Если копия необработанных дескрипторов впоследствии закрыта, это может привести к сбою последующего ReleaseHandle вызова, так как закрытие выполняется на том же дескрипторе, который теперь является недопустимым.
Существует ряд способов, в которых может произойти неправильное дублирование дескрипторов:
Найдите вызовы DangerousGetHandle метода. Вызовы этого метода должны быть чрезвычайно редкими, и все, что вы найдете, должны быть окружены вызовами DangerousAddRef вызовов и DangerousRelease методов. Эти последние методы указывают область кода, в которой можно безопасно использовать необработанное значение дескриптора. Вне этого региона или если число ссылок никогда не увеличивается в первую очередь, значение дескриптора может быть недопустимо в любое время вызовом или Close другим потокомDispose. После отслеживания всех использования DangerousGetHandle следует следовать пути необработанного дескриптора, чтобы убедиться, что он не передается некоторым компонентам, который в конечном итоге вызовет
CloseHandleили другой низкоуровневый собственный метод, который выпустит дескриптор.Убедитесь, что код, используемый для инициализации SafeHandle с допустимым значением необработанного дескриптора, владеет дескриптором. Если вы формируете SafeHandle вокруг дескриптора код не владеет без установки
ownsHandleпараметраfalseв базовом конструкторе, то и SafeHandle реальный владелец дескриптора может попытаться закрыть дескриптор, что приведет к ошибке в ReleaseHandle случае SafeHandle потери гонки.SafeHandle При маршалинге между доменами приложений убедитесьSafeHandle, что используемая производная функция помечена как сериализуемая. В редких случаях, когда класс, производный от SafeHandle него, был сериализуем, должен реализовать ISerializable интерфейс или использовать один из других методов для управления процессом сериализации и десериализации вручную. Это необходимо, так как действие сериализации по умолчанию заключается в создании битового клона закрытого значения необработанного дескриптора, что приводит к двум SafeHandle экземплярам, которые думают, что они имеют один и тот же дескриптор. Оба будут пытаться вызвать ReleaseHandle один и тот же дескриптор в какой-то момент. SafeHandle Второй, чтобы сделать это, завершится ошибкой. Правильный курс действия при сериализации SafeHandle является вызов
DuplicateHandleфункции или аналогичную функцию для собственного типа дескриптора, чтобы сделать отдельную копию юридической дескриптор. Если тип дескриптора не поддерживает этот тип, SafeHandle он не может быть сериализуем.Возможно, можно отслеживать, где дескриптор закрывается рано, что приводит к сбою при ReleaseHandle вызове метода, поместив точку останова отладчика в собственную подпрограмму, используемую для освобождения дескриптора, например
CloseHandleфункции. Это может быть невозможно для сценариев стресса или даже средних функциональных тестов из-за тяжелого трафика такие подпрограммы часто имеют дело. Это может помочь инструментировать код, который вызывает собственный метод выпуска, чтобы записать удостоверение вызывающего объекта или, возможно, полную трассировку стека, а также значение дескриптора, выпущенного. Значение дескриптора можно сравнить со значением, сообщаемым этим MDA.Обратите внимание, что некоторые собственные типы дескрипторов, такие как все дескрипторы Win32, которые можно освободить с помощью функции, совместно используют одно и то же пространство имен дескриптора
CloseHandle. Ошибочное освобождение одного типа дескриптора может вызвать проблемы с другим. Например, случайно закрывая дескриптор событий Win32 дважды может привести к преждевременному закрытию не связанного дескриптора файлов. Это происходит, когда дескриптор освобождается, а значение дескриптора становится доступным для отслеживания другого ресурса, потенциально другого типа. Если это происходит и за ним следует ошибочный второй выпуск, дескриптор несвязанного потока может быть недопустим.
Влияние на среду выполнения
Этот MDA не влияет на среду CLR.
Выходные данные
Сообщение, указывающее, что SafeHandleCriticalHandle не удалось правильно освободить дескриптор. Рассмотрим пример.
"A SafeHandle or CriticalHandle of type 'MyBrokenSafeHandle'
failed to properly release the handle with value 0x0000BEEF. This
usually indicates that the handle was released incorrectly via
another means (such as extracting the handle using DangerousGetHandle
and closing it directly or building another SafeHandle around it."
Конфигурация
<mdaConfig>
<assistants>
<releaseHandleFailed/>
</assistants>
</mdaConfig>
Example
Ниже приведен пример кода, который может активировать releaseHandleFailed MDA.
bool ReleaseHandle()
{
// Calling the Win32 CloseHandle function to release the
// native handle wrapped by this SafeHandle. This method returns
// false on failure, but should only fail if the input is invalid
// (which should not happen here). The method specifically must not
// fail simply because of lack of resources or other transient
// failures beyond the user’s control. That would make it unacceptable
// to call CloseHandle as part of the implementation of this method.
return CloseHandle(handle);
}