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

标签 c# c pinvoke

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

问题:这可能并且安全吗?如果可以,如何实现?

最佳答案

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

您必须担心该对象需要保持固定多长时间。最多几秒钟就可以了,但如果长时间保持固定状态,就会对 GC 造成相当大的损害。这是 GC 必须不断绕过的一 block 石头。而且堆段永远无法回收,单个对象可能会花费您几兆字节。

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

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

关于c# - 在非托管内存中保存对托管对象的引用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32295586/

相关文章:

C# 输出程序集文件名 (csproj)

c# - SerialPort.ReadLine() 返回垃圾

c++ - 获取内存地址的值

c - 需要帮助尝试根据用户输入计算平均值。 C

c# - Process.Start() 继续运行我的 .exe 作为后台进程 MVC ASP.Net

c# - 单元测试 EntityFrameworkCore IEntityTypeConfiguration<T>

c - NASM直接访问声卡(无操作系统)

c# - 使用 p/Invoke 的 x64 版本的 .net 应用程序崩溃

c# - 从 Delphi DLL 发送二进制数据做一个 C# 应用程序

c# - PowerShell 中内联 C# 中的 ScriptBuilder(2.0 及更高版本)