Подтвердить что ты не робот

Зачем использовать FinalReleaseComObject вместо ReleaseComObject?

Я знаю, что основное отличие: ReleaseComObject уменьшает только один счетчик на один, а FinalReleaseComObject уменьшает его до нуля.

Так что я обычно слышу, звоните FinalReleaseComObject, потому что тогда вы уверены, что COM-объект действительно выпущен.

Но это заставляет меня задуматься, есть ли смысл в этом счетчике? Разве вы не нарушаете этот механизм, если всегда звоните FinalReleaseComObject. Если этот счетчик не один, прежде чем вы вызываете ReleaseComObject, разве нет причины для этого?

Что может привести к тому, что он будет выше одного, если это не должно быть?

Спасибо заранее.

PS: Мой COM-опыт состоит только из Excel Interop. Не уверен, что этот вопрос является локальным для этого домена (т.е. Вне Office Interop, FinalReleaseComObject не часто используется).

Обновление 1

статья Дэн упомянул об использовании ReleaseComObject, когда закончите. Как я понимаю из статьи , это обычный способ. Я думаю, что если вы будете делать это последовательно, он должен работать нормально. В комментарии к статье автор предлагает кому-то позвонить ReleaseComObject в цикле, пока он не будет действительно выпущен (статья - с 2006 года, поэтому это аналог вызова FinalReleaseComObject). Но он также заявляет, что это может быть опасно.

Если вы действительно хотите, чтобы RCW вызывал Release() в определенной точке кода, вы можете вызвать ReleaseComObject() в цикле до тех пор, пока возвращаемое значение не достигнет нуля. Это должно гарантировать, что RCW вызовет Release(). Однако, если вы это сделаете, будьте предупреждены, когда другие управляемые ссылки попытаются использовать этот RCW, это вызовет исключение. "

Это заставляет меня думать, что на самом деле не всегда стоит называть FinalReleaseComObject, поскольку вы можете вызывать исключения в другом месте. Как я вижу сейчас, вы должны только называть это, если вы абсолютно уверены, что можете.

Тем не менее, у меня мало опыта в этом вопросе. Я не знаю, как я могу быть уверен. Если счетчик увеличивается, когда этого не должно быть, не лучше ли исправить эту проблему? Если это так, то я бы сказал, что FinalReleaseComObject является скорее взломом, чем лучшей практикой.

4b9b3361

Ответ 1

Некоторая преамбула...

A Runtime Callable Wrapper (RCW) только вызывает IUnknown.AddRef один раз на неуправляемом COM-интерфейсе, который он обертывает. Тем не менее, RCW также поддерживает отдельный подсчет количества управляемых ссылок на RCW. Это отдельный счет управляемых ссылок, который уменьшается при вызове маршала. ReleaseComObject. Когда количество управляемых ссылок достигает нуля, RCW вызывает IUnknown.Release один раз на неуправляемом COM-интерфейсе.

Marshal.FinalReleaseComObject передает управляемый счетчик ссылок в ноль с помощью одного вызова и, таким образом, немедленно вызывает завершенный неуправляемый метод IUnknown.Release(предполагая, что счетчик управляемых ссылок не был уже равен нулю).

Итак, почему есть и Marshal.ReleaseComObject и Marshal.FinalReleaseComObject? Вызов Marshal.FinalReleaseComObject просто избегает необходимости писать цикл, который вызывает Marshal.ReleaseComObject, пока он не вернет 0, когда вы хотите указать, что вы закончили действительно, используя COM-объект сейчас.

Зачем использовать Marshal.ReleaseComObject или Marshal.FinalReleaseComObject? Я знаю две причины:

Во-первых, убедитесь, что неуправляемые ресурсы (такие как дескрипторы файлов, память и т.д.), используемые обернутым COM-объектом, освобождаются как можно скорее в результате вызванного вызова неуправляемого метода IUnknown.Release(),

Во-вторых, убедитесь, что поток, вызывающий неуправляемый метод IUnknown.Release(), находится под вашим контролем, а не поток финализатора.

Без вызовов к одному из этих методов маршала финализатор RCW в конечном итоге вызовет неуправляемый метод IUnknown.Release() через некоторое время после сбора мусора RCW.

Для получения подробных сведений см. запись в блоге Visual С++ Team Смешение детерминированной и недетерминированной очистки