涉及gcroot<>的崩溃本机线程正在运行时进行垃圾回收

时间:2013-12-28 22:47:54

标签: .net garbage-collection c++-cli

我有原生C ++对象Object1,其中包含对托管对象的引用:

   class Object1 
   {
      Object2* parent_;
      gcroot<Observer^> obs_;

      // ctor
      Object1(Object2* parent, Observer^ obs) : parent_(parent), obs_(obs) {} 

      void Execute(void)
      {
         parent_->Execute2(obs_);
      }
   };

函数Execute2()是另一个本机对象的成员,并执行如下代码:

void Object2::Execute2(Observer^ obs)
{
... allocate some managed object data = gcnew(...

   obs->OnNext(data);

用例是Object1被创建并放入队列。然后一个单独的本机线程弹出队列, 调用执行 - &gt; Execute2 - &gt; OnNext()然后删除非托管Object1

托管对象恰好来自并实现了Reactive Extensions IObserver接口,这就是我在其上调用OnNext()的原因。 显然在重负载(暗示GC被调用)程序崩溃由于InvalidOperationException(“Handle未初始化。”) 使用以下崩溃转储堆栈(清理以使其更具可读性):

[Managed to Native Transition]  
mscorlib.dll!System.Runtime.InteropServices.GCHandle.FromIntPtr(System.IntPtr value)
<Module>.gcroot<Observer^>.->()
<Module>.Object2.Execute2(Observer obs)
<Module>.Object1.Execute() 
[Native to Managed Transition]  

但是,传递给FromIntPtr的值不为null,这是导致异常的一种方法。而且,我相当自信 在构造Object1时,无法将null句柄作为obs参数传递(但请参见下面的第3点)。

因此,我想到的只有三个可能的崩溃原因是:

  1. gcroot中保存的管理对象已被处理

  2. GC将引用移动到托管对象,然后非托管线程尝试从错误的指针获取GCHandle。也就是说,GC尚未修复它以引用托管对象的新位置。

  3. 托管对象在存储到Object1之前已收集。这段代码路径如下:

    C#代码:

         Observer obs = new Observer;
         SomeManagedObject.StoreObserver(obs);
    

    C ++ / CLI代码:

         StoreObserver(Observer^ obs)
         {
           Object1 obj1 = new Object1(ptrObject2, obs);
    
  4. 我倾向于排除1作为原因,因为只有在删除Object1时才会调用gcroot析构函数。直到那个都没有发生 已经返回对Execute的调用。因此,GC不应收集gcroot所持有的托管对象。

    2似乎是可能的,因为GC不知道非托管线程,这些可以在GC进程的“中间”执行。 通常,您会发现不需要固定存储在gcroot中的托管对象的声明。这似乎是 应该的情况。

    我很难想象3会发生什么。

    任何人都可以对此有所了解并支持或显示我的推理错误吗? 崩溃是间歇性的,我想在尝试使用固定指针之前得到一些反馈。

0 个答案:

没有答案