Освобождает ли CLR память от COM-объектов? - PullRequest
1 голос
/ 30 июня 2009

Я работаю над надстройкой Outlook, где я создаю много COM-объектов (почта Outlook, папка Outlook и т. Д.). Насколько я понимаю, поскольку эти объекты являются объектами COM, CLR не освобождает память от этих объектов, и мне придется позаботиться об освобождении памяти от этих объектов. Поэтому для освобождения памяти от этих объектов я использую

Marshal.ReleaseComObject (объект);

Но, к сожалению, это не похоже на работу. Затем я поместил оператор GC.Collect () после Marshal.ReleaseComObject (Object), и это сработало. После этого я не получил никаких исключений, связанных с памятью. Мой вопрос заключается в том, что если CLR может передавать память из COM-объектов, то почему он не делает это сам по себе. и если это невозможно, то как работает оператор GC.Collect () в моем случае.

Ответы [ 2 ]

7 голосов
/ 30 июня 2009

Вам необходимо хорошо понимать Runtime Callable Wrapper , чтобы использовать COM с .Net. По сути, все, что у вас есть в вашем .Net-коде, которое является ссылкой на COM-объект, на самом деле является ссылкой на RCW. RCW управляет счетчиком ссылок на базовый COM-объект, подсчитывая, сколько ссылок на него, и когда количество ссылок на него падает до 0, он вызовет Release (один раз) для базового объекта. Пока RCW активен, он будет поддерживать единственную ссылку на объект COM.

API ReleaseComObject уменьшит счетчик ссылок на RCW на 1. Если это приведет к счетчику ссылок на RCW к 0, тогда RCW вызовет Release для объекта COM, в противном случае - нет. Существует также FinalReleaseComObject, который заставит счетчик ссылок на RCW перейти к 0 (таким образом, вызовет RCW Release), хотя это довольно рискованно, если у вас есть другие выдающиеся ссылки на RCW, так как они, вероятно, приведут к ошибке .

«Обычно», ссылки на RCW управляются, когда объекты, на которые есть ссылка на него, являются сборщиком мусора - это объясняет, почему вы увидели, что COM-объект был освобожден, когда вы принудительно собрали сборщик мусора. Это, в сочетании с тем, что мы знаем о том, как работает RCW, говорит нам о том, что на RCW были и другие ссылки, которые вам также «понадобились бы» для вызова ReleaseComObject, чтобы вызвать его на Release.

Вызов ReleaseComObject является своего рода завершением работы среды выполнения .Net, и вы должны быть очень осторожны, чтобы управлять всеми созданными ссылками. Некоторые из созданных ссылок являются «неявными» ссылками - они возникают из-за таких действий, как вызов свойств, которые возвращают ссылки, которые вы затем вызываете. Иногда это называют проблемой «слишком много точек», когда вы делаете что-то вроде этого:

object.foo.blah.baz.something()

"foo", "blah" и "baz", вероятно, являются ссылками на некоторый COM-объект, о котором вам нужно подумать.

0 голосов
/ 30 июня 2009

Вы пытались выделить память после Marshal.ReleaseComObject? Потому что, вы знаете, сборщик мусора будет работать по собственному желанию, что обычно означает, когда выделяется память, а не только когда вы думаете, что она должна работать (если, конечно, вы не вызываете GC.Collect).

До сих пор у меня не было проблем с автоматическим освобождением COM-объектов, и я вызывал Marshal.ReleaseComObject только тогда, когда я хочу, чтобы COM-сервер был немедленно выключен.

...