如何解决用于P /调用访问的固定数据
我正在使用P / Invoke将数据从C#代码传递到C ++代码,反之亦然。到目前为止,一切正常。
最近我读了一些文章(例如this one),这些文章需要固定这些数据,因为在C ++执行任务时,GC可能会重新排列或删除它们。
我查阅了一些Microsoft文章,但对我而言,关于何时需要手动完成固定并不清楚。我了解this文章的方式是CLR确保GC收集时不会出现任何问题。它可以通过固定数据或将其复制到GC无法收集的非托管内存中来实现。因此,对我而言,这意味着程序员无需担心固定问题。 article中的示例也未显示任何固定。我仍然不确定我的结论是否正确。
进一步挖掘,我发现了一些我在代码中使用的特定数据类型的更多信息:
int
,long
:按值传递-因此不得固定。但是ref int
呢?
IntPtr
:我使用AllocHGlobal()在非托管内存中分配空间。 GC不会碰它。因此无需固定。
byte[]
:通过引用但已自动固定。请参见here:作为一种优化,在编组过程中,固定而不是复制的仅包含blittable成员的blittable类型和类的数组。
string
:通过引用但已自动固定。请参见here:在编组诸如String之类的对象时会自动执行钉扎,但是您也可以使用GCHandle类手动钉扎内存。
string[]
,'custom struct with strings'
:我真的不确定。句子“ 固定为字符串[...] 之类的对象时会自动执行钉扎”包括字符串数组和自定义结构吗?
目前,我什么都没有固定,代码也可以正常工作。即使当我强制GC在C ++执行任务时进行收集时。但是,当然这并不意味着它将始终正常运行。 我使用.Net Framework 4.8。
我需要固定提到的数据类型吗?
解决方法
此处的规则取决于您要调用的内容,因此只有在没有具体示例的情况下才可以给出模糊的建议,但是:
如果您通过P / Invoke调用的方法在该P / Invoke调用期间仅使用指针 ,那么:在几乎所有情况下,您都可以接受并传递隐式指针,或在调用周围使用fixed
(即,如果P / Invoke签名仅声明了SomeStruct*
或IntPtr
),就可以正常工作。
如果您通过P / Invoke调用的方法在返回指针之前存储了指针,然后期望该指针有意义(可能是基于回调的异步/完成API),在这种情况下,您需要确保不会移动数据:
- 对于非托管内存(例如来自
AllocHGlobal
的内存:没有必要 - 用于内存降低堆栈(即在此期间不会重新使用堆栈帧):不需要
- (如果您将堆栈存储器与P / Invoke一起使用,但不能满足该条件:您犯了一个严重的设计错误)
- 用于托管内存(堆上的对象等);这就是乐趣的开始;请注意,.NET 5引入了“固定对象堆”(通常用于用于P / Invoke的数组),但除此之外:您需要手动固定
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。