将C ++ / CLI桥接到C#时防止垃圾回收

时间:2015-07-09 05:04:23

标签: c# memory-management garbage-collection c++-cli

我目前正在使用C ++代码库并编写托管C ++ / CLI包装器以启用C#桥接。我的一个托管类包含一个malloc内存的非托管块:

public ref class ManagedFoo
{
public:
   ManagedFoo()  { m_fooData = malloc(AmountNeeded); }
   ~ManagedFoo() { free(m_fooData); } // not sure if this should be a finalizer instead
   void *m_fooData;
};

一个相关的类保存指向该分配块的指针,并将其发送到非托管区域,假定它存在,直到进行特定调用:

public ref class ManagedBar
{
public:
    static void BorrowFooData(ManagedFoo^ f) 
    { 
      TotallyUnmanagedCode(f->m_fooData);
      // The unmanaged code has held onto this pointer for future use
    }
    static void DoneWithFooDataNow() 
    {
      MoreTotallyUnmanagedCode();
      // The unmanaged code is finally done with f->m_fooData at this point
    }
}; 

像这样使用:

ManagedBar^ b = gcnew ManagedBar;
b->BorrowFooData(myFooA);
b->BorrowFooData(myFooB);
b->BorrowFooData(myFooC);
// lots of other code here, where myFoos could potentially become unreferenced

// at some point in the future...
b->DoneWithFooDataNow();

如何才能最好地防止过早的垃圾收集?

我当前的解决方法感觉非常昂贵 - 我在List<ManagedFoo^> keepAlive内添加了ManagedBar个对象,并且BorrowFooData的每次调用只Add fooDoneWithFooDataNow列表。这样,我可以确定引用仍然存在,垃圾收集不会发生。 (keepAlive清除{{1}}列表。)

我实际上没有对这段代码进行压力测试,看到垃圾收集器导致问题,但我确信这只是时间问题。

1 个答案:

答案 0 :(得分:1)

GCHandle类正好用于在非托管代码中存储引用。其文档包括示例。

PS:对于您的问题,是的,处理非托管资源应该在终结器中。如果我没记错的话,如果你包含一个析构函数,你应该从析构函数中显式调用终结器,以防你对象Dispose