Зачем использовать FinalReleaseComObject вместо ReleaseComObject? - PullRequest
33 голосов
/ 01 декабря 2009

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

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

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

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

Заранее спасибо.

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

Обновление 1

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

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

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

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

1 Ответ

35 голосов
/ 01 декабря 2009

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

Среда выполнения Callable Wrapper (RCW) вызывает IUnknown.AddRef только один раз для неуправляемого COM-интерфейса, который обертывает. Однако RCW также ведет отдельный подсчет количества управляемых ссылок, существующих на сам RCW. Это отдельное количество управляемых ссылок, которое уменьшается при вызове Marshal.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 (), находится под вашим контролем, а не потоком финализатора.

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

Подтверждающие сведения см. В записи блога Visual C ++ Team Смешивание детерминированной и недетерминированной очистки

...