在非托管内存中保存对托管对象的引用

时间:2015-08-30 10:32:16

标签: c# c pinvoke

我想将一个C#对象的引用放入非托管内存(C)中,我想作为一个指针(int),当C代码稍后回调到C#时,我想从中获取引用非托管内存,所以我可以解决它,并访问该对象。原因是C代码控制应该使用哪个对象,没有真正的替代方案。我对C代码的控制有限,而C ++ / CLI不是一个选项。

问题:这是否可行且安全,如果是,如何?

3 个答案:

答案 0 :(得分:3)

嗯,这是可能的。主要担心的是你的方案与垃圾收集器非常不兼容,它在压缩堆时会在内存中移动对象。这是你可以停止的东西,你可以固定对象,这样GC就无法移动它。您使用GCHandle.Alloc()来分配GCHandleType.Pinned句柄,并将GCHandle.AddrOfPinnedObject()的返回值传递给您的C代码,可能是通过pinvoke调用。

你必须担心该物体需要多长时间才能保持固定状态。几秒钟,顶部,没关系,但如果你把它固定很长时间,它对GC非常不利。这是道路上的一块岩石,GC经常不得不四处奔走。并且堆段永远不会被回收,单个对象可能会花费你一把兆字节。

在这种情况下,您应该考虑分配非托管内存并将对象复制到其中。使用Marshal.AllocHGlobal()分配Marshal.StructureToPtr()将对象复制到其中。如果您修改对象,可能需要多次,并且C代码也需要更改。

无论哪种方式,对象必须是 blittable ,否则会出现运行时错误。一个昂贵的单词,只意味着对象必须具有简单的字段类型,这是C程序正确读取的类型。不要使用 bool 。小心C程序中的声明,当你弄错它时很容易破坏堆。

答案 1 :(得分:2)

当您控制'分发'和'接收后使用'阶段时,您可以简单地使用List或数组并传递索引。

答案 2 :(得分:1)

可以通过COM和名为COM-Callable Wrappers的CLR创建的代理来使用C#对象。

您只需指定一个GUID程序集属性来标识COM类型库,例如:

[assembly: Guid ("39ec755f-022e-497a-9ac8-70ba92cfdb7c")]

然后使用Type Library Exporter工具( tlbexp.exe )生成可在COM世界中使用的COM类型库(.tlb)文件:

tlbexp.exe YourLibrary.dll

如果你的意思是C#的安全感,那肯定是不安全的,因为你将使用非托管世界中的对象,并且生命周期通过引用计数从COM端控制,而不是CLR的GC。 / p>

相关问题