2013-06-28 4 views
1

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

Фон: Наш программный движок закодирован в неуправляемом C++. Функциональность нашего программного обеспечения расширяется с использованием компонентов COM-объекта для движка. По большей части сам двигатель не нужно менять годами. Однако мы продолжаем создавать дополнительные компоненты для добавления новых функций в наше программное обеспечение. Хотя эти компоненты также были созданы в неуправляемом C++, в течение последних двух лет мы кодировали эти плагины на C#.

До недавнего времени мы подписались на идею Marshal.ReleaseComObject не следует вызывать на неуправляемых объектах COM, используемых в компонентах C#, и вместо этого разрешить сборку RCW и мусора управлять своей жизнью.

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

Есть ли какая-то ошибка, которую мы могли бы сделать, что мешает GC и RCW действовать на этих объектах? Разве идея сбора мусора не означает, что она будет делать то, что необходимо, чтобы обеспечить свободный доступ к памяти при необходимости?

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

Однако, пытаясь разработать согласованный шаблон для использования Marshal.ReleaseComObject, мы обнаружили один случай, в котором мы не уверены, что его можно использовать. Некоторым компонентам необходимо передать возвращаемые значения объекта COM обратно в неуправляемый движок. Компонент никогда больше не увидит возвращаемое значение и (в настоящее время) не может быть уведомлен, когда он больше не используется. Например:

// Unmanaged C++ code 
Engine::Engine() : m_ipDoodadCreator(CLSID_FancyComponent) 
{ 
} 
void Engine::ProcessDoodad() 
{ 
    try 
    { 
     // Smart pointer 
     IDoodadPtr ipDoodad = m_ipDoodadCreator->CreateDoodad(); 
     ... 
     ipDoodad = NULL; // Calls Release... 
    } 
    catch (...) { ... } 
    // At this point the doodad lives on because the RCW is holding a 
    // reference to it. 
} 

// Managed C# Component 
public class FancyComponent : IDoodadCreator 
{ 
    public IDoodad IDoodadCreator.CreateDoodad() 
    { 
     // IDoodad is implmented in unmanaged c++ 
     IDoodad doodad = new IDoodad(); 

     try 
     { 
      ... 

      return doodad; 
     } 
     finally 
     { 
      // Can't do this here because engine doesn't yet have 
      // a reference to doodad. 
      // Marshal.ReleaseComObject(doodad); 
     } 
    } 
} 

До сих пор единственная идея, которую мы можем придумать, чтобы детерминировано Получить RCW выпустить ссылку в этой ситуации было бы переработать двигатель так, что все интерфейсы имеют Cleanup(), вызываемый время от времени, но это потребует много времени и, в некоторых случаях, довольно громоздко реализовать.

tl; dr Есть ли способ заставить RCW освободить ссылку на объект COM, который возвращается в неуправляемую среду?

+0

'IDoodad' должен наследовать от' IUnknown', поэтому вы должны иметь возможность вызывать 'Release', как правило, последний, который я проверил. – Mgetz

+0

Release уменьшает счетчик ссылок. Если что-то еще (RCW) все еще имеет ссылку, doodad продолжает жить. В приведенном выше коде я подразумеваю, что IDoodadPtr - это умный указатель, вызывающий Release, когда он выходит за рамки. – Alias

+0

Вы имеете в виду [COM Callable Wrapper] (http://msdn.microsoft.com/en-us/library/f07c8z1c.aspx)? согласно MSDN, если релиз называется обычно, он освободит объект для сбора мусора. – Mgetz

ответ

-1

Ответ на нашу ближайшую проблему - GC.AddMemoryPressure.

Поскольку мы создаем и ссылаемся на экземпляры RCW не управляемых классов, сборщик мусора не знает память, выделенную для этих объектов. Согласно MSDN помощью этого метода:

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

http://msdn.microsoft.com/en-us/library/system.gc.addmemorypressure.aspx

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

+0

Я не публикую часто, но, похоже, было бы хорошим этикетом добавить комментарий, объясняющий, почему вы проголосовали за ответ, поэтому автор может понять, что неправильно/бесполезно ... – Alias

1

, но на практике мы начали возникают проблемы с памятью с нашим программным обеспечением

Это классическая проблема взросления боли. Программное обеспечение никогда не становится меньше, никто в команде не присуждается за письмо отрицательный код. Добавьте все больше и больше функций, ваша программа никогда не использует меньше память. Стандартная диагностика заключается в том, что потребление первого гигабайта виртуальной памяти занимает очень много времени. Второй гигабайт исчез очень быстро.

Где вы сейчас находитесь: очень непродуктивно, вы беспокоитесь о горстке мегабайт. Просто переведите переключатель в не-проблему. Скомпилируйте собственный код в 64-разрядный. Вы не получите никаких возражений от управляемого кода, x64-джиттер уже знает, как это сделать без любых изменений.

+0

Я думаю, вы правы в том, что нам нужно искать другие стратегии. Один из тех, что мы использовали не так давно, - это включить флаг с большим адресом. Но в то время как переход на x64 не может быть «непроизводительным» в том смысле, что мы будем извлекать долгосрочные выгоды, он также нигде не близок к легкому, а не тому, что мы можем выделить время для решения ближайшей проблемы; у нас есть много устаревшего кода C++, где выбор типов не был сделан с возможным переходом на x64 в виду ... – Alias

Смежные вопросы