我有原生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点)。
因此,我想到的只有三个可能的崩溃原因是:
gcroot中保存的管理对象已被处理
GC将引用移动到托管对象,然后非托管线程尝试从错误的指针获取GCHandle。也就是说,GC尚未修复它以引用托管对象的新位置。
托管对象在存储到Object1
之前已收集。这段代码路径如下:
C#代码:
Observer obs = new Observer;
SomeManagedObject.StoreObserver(obs);
C ++ / CLI代码:
StoreObserver(Observer^ obs)
{
Object1 obj1 = new Object1(ptrObject2, obs);
我倾向于排除1作为原因,因为只有在删除Object1
时才会调用gcroot析构函数。直到那个都没有发生
已经返回对Execute的调用。因此,GC不应收集gcroot
所持有的托管对象。
2似乎是可能的,因为GC不知道非托管线程,这些可以在GC进程的“中间”执行。 通常,您会发现不需要固定存储在gcroot中的托管对象的声明。这似乎是 应该的情况。
我很难想象3会发生什么。
任何人都可以对此有所了解并支持或显示我的推理错误吗? 崩溃是间歇性的,我想在尝试使用固定指针之前得到一些反馈。