C# 防止非托管代码中使用的托管引用的垃圾回收 我的C语言应用程序使用包裹的C++代码进行计算。

C# 防止非托管代码中使用的托管引用的垃圾回收 我的C语言应用程序使用包裹的C++代码进行计算。,c#,garbage-collection,c++-cli,wrapper,C#,Garbage Collection,C++ Cli,Wrapper,C++标题: __declspec(dllexport) void SetVolume(BYTE* data, unsigned int width); C++/CLI包装器: void SetVolume(array<Byte>^ data, UInt32 width) { cli::pin_ptr<BYTE> pdata = &data[0]; pal->SetVolume(pdata, width); } C++ >代码> S

C++标题:

__declspec(dllexport) void SetVolume(BYTE* data, unsigned int width);
C++/CLI包装器:

void SetVolume(array<Byte>^ data, UInt32 width) 
{
    cli::pin_ptr<BYTE> pdata = &data[0];
    pal->SetVolume(pdata, width); 
}

C++ >代码> StItStudio函数启动<强>异步< /强>计算>code>voxelArr不再从托管端引用,而是被垃圾收集

如何防止此引用的垃圾收集,直到非托管代码完成其工作,而不将
voxelArr
声明为全局变量?创建数组的副本不是一个选项,因为实际上有很多数据。
startCalc()
内部的活动等待也不好。

您可以使用
(体素阵列,
手动锁定阵列,以便GC不会移动或清理它


然后,当您知道该方法已完成时,您必须处理该问题,这需要某种形式的回调才能完成。

当前方法的另一种替代方法:

考虑再次使阵列全局化,在开始时创建并固定一次,然后在需要时重用它。像这样大的对象不应该一时兴起创建。只有在需要以较大的尺寸重新创建时,才能取消绑定并释放它


将对象存储在全局池中将防止其被垃圾收集。严格来说,您不必担心固定这么大的对象,但这样做是为了保持一致性

谢谢,看起来正是我需要的。这是否意味着我不需要在C++CLI?@ VladL中定义代码>数据< /代码>变量,如果你把它放在C++中,你就不需要在C++中把它插入。也就是说,pin_ptr允许您作为指针访问数据,因此您可能仍然希望它存在。你也可以在C++的边上坚持PixpTR,因为它只是在内部做这个。@ VDLL注意到,你可以完全在C++ +CLI包装器中完成这一操作,而不是在C语言中完成。这是我的偏好,因为它会使API更干净…防止它被收集不是你唯一的问题,你还需要防止它在内存中移动。所以你也必须把它钉起来(正如里德•科普西所建议的)@ Hugunune,我认为代码> Pij-PTR < /代码>阻止移动它,不是吗?要考虑创建副本不是这里最好的方法。至少,您可以从取消钉住它中解脱出来,GC也会更快乐。是的,这意味着它被钉住(也可以免于垃圾收集),如果您只需要在cli SetVolume运行时使用它,我认为您不需要其他任何东西。然而,一旦包装器setVolume函数结束,它将被取消固定,并可能被收集或移动。想想看,该语句是毫无意义的。一个托管对象不能大于2个JigabyTes,即使在64位模式下。如果它必须重复使用这个数组,它可能是一个选项,但是我只需要它一次加载数据并将其传递给C++计算。
public startCalc()
{
    byte[] voxelArr = File.ReadAllBytes("Filtered.rec");
    palw.SetVolume(voxelArr, 490);
    //GC.KeepAlive(voxelArr); makes no sense
}