Зачем использовать 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 — это скорее хак, чем лучшая практика.


person Matthijs Wessels    schedule 01.12.2009    source источник
comment


Ответы (1)


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

Вызываемая оболочка времени выполнения (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++ Смешивание детерминированных и недетерминированная очистка

person Dan Blanchard    schedule 01.12.2009
comment
Из документации по методу Marshal.ReleaseComObject по адресу msdn.microsoft. .com/en-us/library/ : чтобы убедиться, что вызываемая оболочка времени выполнения и исходный COM-объект освобождены, создайте цикл, из которого вы вызываете этот метод, пока возвращаемый счетчик ссылок не достигнет нуля. - person AMissico; 01.12.2009