我目前正在使用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
foo
个DoneWithFooDataNow
列表。这样,我可以确定引用仍然存在,垃圾收集不会发生。 (keepAlive
清除{{1}}列表。)
我实际上没有对这段代码进行压力测试,看到垃圾收集器导致问题,但我确信这只是时间问题。
答案 0 :(得分:1)
GCHandle
类正好用于在非托管代码中存储引用。其文档包括示例。
PS:对于您的问题,是的,处理非托管资源应该在终结器中。如果我没记错的话,如果你包含一个析构函数,你应该从析构函数中显式调用终结器,以防你对象Dispose
。