Освобождение COM-объектов Excel

У меня есть код автоматизации Excel, который использует COM-объекты Excel. Из других сообщений SO я знаю, что нужно сделать следующее чтобы освободить объекты при первой возможности:

Excel.Range rng = GetSomeRange();

// do something with rng...

Marshal.ReleaseComObject(rng);

Однако, если я перебираю ячейки в диапазоне, правильна ли следующая процедура?

Excel.Range rng = GetSomeRange();
foreach (Excel.Range r in rng)
{
    // do something with r
    Marshal.ReleaseComObject(r); // release at earliest possible convenience
}

Marshal.ReleaseComObject(rng);

В чем я не уверен, так это в том, что если я выпущу каждый r в rng, а затем я также выпущу rng, я эффективно выпущу rng дважды или правильно выпуская дополнительные ссылки r на rng и сам rng?

Спасибо за рекламу!

ИЗМЕНИТЬ

Я выбрал последнюю стратегию:

Excel.Range rng = GetSomeRange();
foreach (Excel.Range r in rng)
{
    // do something with r
    Marshal.ReleaseComObject(r); // release at earliest possible convenience
}

Marshal.ReleaseComObject(rng);

что значительно уменьшило память ...

еще раз - всем спасибо!


person Pat Mustard    schedule 30.04.2015    source источник
comment
Вероятно, вам не нужно явно освобождать второстепенные COM-объекты, такие как r. См. Этот ответ stackoverflow.com/a/159419/141172   -  person Eric J.    schedule 30.04.2015


Ответы (1)


К сожалению, существует много ложной информации. Сначала позвольте мне четко сформулировать ответ:

Вам не нужно звонить Marshal.ReleaseComObject в большинстве случаев. Почему? Потому что сборщик мусора сделает это за вас. * Обратите внимание, что я сказал большинство, вы можете обнаружить, что удержание многих ссылок вызывает проблемы (по любой причине). Только в этих случаях, если вы решите позвонить Marshal.ReleaseComObject.

Ссылка:

Кристофер, у нас всегда были автоматические релизы для COM-объектов, поскольку сборщик мусора определяет, что ему необходимо их очистить. Их не убирают сразу, но убирают в какой-то момент позже, после одной или двух сборок мусора. Я подтвердил это с командой.

Они сказали:

В зависимости от типа приложения в блоге это не имеет особого значения, если люди испортят свое приложение, они потерпят неудачу, и они получат очевидные ошибки при подсчете ссылок. В случаях, когда их код загружается внутри офиса, а не наоборот, это вызывает гораздо большее беспокойство, потому что вы можете в конечном итоге выпустить чью-то ссылку, тогда могут возникнуть проблемы, которые они не замечают в своем коде, но кого-то ломают. Вместо этого надстройка elses office.

Итак, дело в том, что, хотя ReleaseComObject более детерминирован, обычно в этом нет необходимости, поскольку сборщик мусора будет делать то же самое.

Также я предлагаю вам прочитать Marshal.ReleaseComObject считается опасным.

Если у вас возникнет соблазн вызвать «Marshal.ReleaseComObject», можете ли вы быть на 100% уверены, что никакой другой управляемый код все еще не имеет доступа к RCW? Если ответ «нет», не называйте его. Самый безопасный (и самый разумный) совет - полностью избегать использования Marshal.ReleaseComObject в системе, где компоненты могут повторно использоваться и обновляться с течением времени.

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

person Jesse Good    schedule 30.04.2015
comment
Отличный ответ, спасибо, @Jesse. В моей системе я создаю Range объектов каждые пару секунд, и их количество достигает ~ 100 000 за сеанс. В качестве возможной последовательности (я подозреваю) я вижу объем памяти Excel, который иногда превышает 800 МБ, что не может быть правильным IMO. Для ReleaseComObject я использую это только тогда, когда уверен, что мои объекты больше не нужны. Например, когда они используются в области видимости и больше не требуются, когда они выходят за рамки. Возможно ли, что такое большое количество созданных объектов приведет к крупномасштабным «утечкам», как я описал? Еще раз спасибо! - person Pat Mustard; 30.04.2015
comment
@PatMustard: Если вы создаете столько Range объектов, возможно, из-за этого используется память. Есть ли причина, по которой вы создаете так много? Например, лучше было бы читать / обновлять за один раз. Кроме того, вы также можете поэкспериментировать с GC.Collect(), но я бы оставил это на крайний случай. - person Jesse Good; 30.04.2015
comment
К сожалению, мне нужно сделать это так, поскольку мой лист должен быть достаточно надежным, чтобы обрабатывать изменения во время выполнения для диапазонов, чтобы реагировать на изменение значений и т. Д. Я реализовал последнюю стратегию (освобождая ссылочные компоненты r, а также сам rng, и я вижу значительное улучшение потребления памяти). Таблица связана с тиковыми данными в реальном времени, поэтому я действительно не хочу идти по маршруту GC. В общем, сейчас все намного улучшилось - спасибо за совет ... это очень помогло :) - person Pat Mustard; 30.04.2015