Объект получает мусор во время выполнения? - PullRequest
3 голосов
/ 17 февраля 2012

Рассмотрим следующий фрагмент кода C ++ / CLI:

public ref class MyData
{

private:
  UnmanagedObject* pobj;

public:
  MyData()
  {
    pobj = ... // acquire unmanaged pointer
  }

  !MyData()
  {
    delete pobj;  // finalizer
    pobj = NULL;
  }

  void DoSomething()
  {
    // next line calls a native method that has no knowledge of .NET
    CallToNativeMethod(data->pobj);
  }

  static void Test()
  {
    MyData^ data = gcnew MyData();
    data->DoSomething()
  }
}

Этот класс представляет собой .NET-оболочку для некоторого неуправляемого API.В моем проекте я в настоящее время имею дело с трудной для отслеживания ошибкой - кажется, что MyData собирает мусор, пока метод DoSomething() все еще выполняется.Вот что, я считаю, происходит:

  1. Вызывается статический метод Test(), который создает экземпляр MyData
  2. Метод экземпляра DoSomething() называется
  3. DoSomething() вызывает собственный метод
  4. Пока (!) Выполняется собственный метод, сборщик мусора собирает экземпляр MyData и вызывает финализатор
  5. Финализатор удаляетpobj, который используется нативным методом , который все еще выполняется
  6. Ну ... программа вылетает

Мои два вопроса:

  1. Возможен ли описанный выше сценарий на самом деле?Я не могу смириться с тем фактом, что объект может быть завершен, пока метод экземпляра все еще выполняется ...
  2. Какой хороший способ решить эту проблему (т.е. предотвратить сбор объекта)пока это "безопасно" сделать)?Изменение любой переменной экземпляра после , выполненного нативным методом, делает свое дело, но кажется, что это нереально.

EDIT (некоторыедополнительная информация): код падает с AccessViolationException, который всплывает из нативного метода, и может быть пойман с помощью try..catch в Test().Для отладки я вставил пару вызовов регистрации, которые показывают следующий порядок выполнения:

  1. Введен собственный метод (но никогда не завершен)
  2. Финализатор выполнен
  3. Исключение поймано

1 Ответ

0 голосов
/ 26 июля 2013

Вы должны добавить GC :: KeepAlive (data) в конец метода Test ().

Имейте в виду, что если CallToNativeMethod вызывает вызов в другом потоке и немедленно возвращается,тогда объект управляемых данных и ссылка на сборщик мусора довольно быстро выйдут из области видимости, и тогда возникнет опасность повторного сбора мусора.В этом случае вам потребуется создать некоторый код уведомления, который вызывает KeepAlive и до тех пор, пока он не получит сигнал.

...