Этот объект COM подлежит сборке мусора? - PullRequest
6 голосов
/ 21 января 2011

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

Структура исходного кода аналогична приведенной ниже:

static void Main(string[] args)
{
    MyEventGen gen = new MyEventGen();
    WeakReference wr = new WeakReference(gen);
    gen.ReceiveDataArray += 
            new _IMyEventGenEvents_ReceiveDataArrayEventHandler(gen_ReceiveDataArray);
    while (true)
    {
        Thread.Sleep(1000);
        Console.WriteLine(wr.IsAlive);
    }
}

static void gen_ReceiveDataArray(ref Array indices, ref Array values)
{
    // do nothing
}

alt text

Что я знаю до сих пор:

  • Из того, что я понимаю, объект gen никоим образом не должен собираться мусором. Поскольку объект все еще активен в области действия Main.Но результат пока показывает, что объект был собран GC.

  • Объект собирается только при сборке мусора как Выпуск и запуск без отладки .Запуск отладочных сборок / запуск обоих режимов в отладчике - это нормально.

  • Программа напечатает первый «False» точно после первой коллекции Gen # 0 .

  • Получив доступ к объекту в цикле while, например, Console.WriteLine(gen.ToString()), защитите его от GC'd!

  • Добавив еще одинСтатическое поле класса Program для сохранения его ссылки также предотвращает его от GC'd.

  • Пытаясь с различной загрузкой данных, я обнаружил, что GC собирает объект только тогда, когда частные байты достигаютсвыше порога ~ 3X МБ.

  • При проверке с помощью CLRProfiler указанный объект был GC'd как подозреваемый.

Я пропустил некоторые важные концепции .NET GC?Можно ли получить причину того, что объект был GC'd?Возможно, это известная ошибка GC?

Я использую VS 2008 + .NET 3.5 SP1.Цените ваши мысли.Спасибо!

Ответы [ 3 ]

7 голосов
/ 21 января 2011

Нет необходимости использовать COM-объект для воспроизведения этого. Учтите следующее:

public class MyEventGen
{
    public event Action ReceiveDataArray;
}

class Program
{
    public static void Main()
    {
        var gen = new MyEventGen();
        var wr = new WeakReference(gen);
        // this is the last time we access the 
        // gen instance in this scope so after this line it
        // is eligible for garbage collection
        gen.ReceiveDataArray += new Action(gen_ReceiveDataArray);

        // run the collector
        GC.Collect();
        while (true)
        {
            Thread.Sleep(1000);
            Console.WriteLine(wr.IsAlive);
        }
    }

    static void gen_ReceiveDataArray()
    {
    }
}

Запустите его в режиме выпуска, и он будет демонстрировать то же поведение. Объект gen выпадает из области видимости и подвергается сборке мусора, потому что нет ничего, чтобы поддерживать его во время выполнения цикла.

2 голосов
/ 21 января 2011

Ваши COM-объекты могут быть уничтожены, как только их эквиваленты .NET исчезнут из программы. В последний раз gen используется, когда выполняется вызов ReceiveDataArray += ....

Вы должны добавить вызов к GC.KeepAlive(gen) в той точке программы, где допустимо выполнение очистки. В качестве альтернативы, если она должна оставаться в живых до выхода из программы, вы можете добавить ее в качестве поля static.

2 голосов
/ 21 января 2011

Ни gen, ни wr не остаются активными в основной области во время выполнения цикла while.Вы заключили первые три строки в фигурные скобки, которые помещают эти переменные в дочернюю область, которая завершается до начала цикла while.

...