C# P/Invoke访问的Pin数据
我使用p/Invoke将数据从C++代码传递到C++代码,反之亦然。到目前为止,这一切都很好 <>最近我读了一些文章(例如),需要对这些数据进行钉扎,因为GC在C++执行任务时可能会重新排列或删除它们。 我查阅了一些微软的文章,但对我来说,它们并不完全清楚何时需要手动进行钉扎。我对本文的理解是,CLR确保在GC收集数据时不会出现任何问题。它通过将数据固定或复制到GC不收集的非托管内存中来实现。所以对我来说,这意味着程序员不需要考虑钉住。本文中的示例也没有显示任何固定。我仍然不确定我的结论是否正确 进一步挖掘,我发现了我在代码中使用的特定数据类型的更多信息:C# P/Invoke访问的Pin数据,c#,c++,clr,pinvoke,C#,C++,Clr,Pinvoke,我使用p/Invoke将数据从C++代码传递到C++代码,反之亦然。到目前为止,这一切都很好 最近我读了一些文章(例如),需要对这些数据进行钉扎,因为GC在C++执行任务时可能会重新排列或删除它们。 我查阅了一些微软的文章,但对我来说,它们并不完全清楚何时需要手动进行钉扎。我对本文的理解是,CLR确保在GC收集数据时不会出现任何问题。它通过将数据固定或复制到GC不收集的非托管内存中来实现。所以对我来说,这意味着程序员不需要考虑钉住。本文中的示例也没有显示任何固定。我仍然不确定我的结论是否正确 进
int
,long
:按值传递-因此不能固定。但是ref int
呢
IntPtr
:我使用AllocHGlobal()在非托管内存中分配空间。总司令没有触及这一点。所以不需要钉住
byte[]
:通过引用传递,但自动固定。请参阅:作为一种优化,在封送处理期间,将固定只包含可blittable成员的可blittable类型和类的数组,而不是复制这些数组
string
:通过引用传递,但自动固定。请参阅:在封送处理对象(如字符串)时,会自动执行固定,但是您也可以使用GCHandle类手动固定内存
string[]
,“带字符串的自定义结构”
:这里我真的不确定。“在封送处理字符串[…]等对象时自动执行固定”这句话是否包括字符串数组和自定义结构
目前,我没有任何pin码,代码工作正常。甚至当我强制GC收集的同时C++正在执行它的任务。当然,这并不意味着它总是可以正常工作。
我使用.NETFramework4.8
我是否需要对所提到的数据类型进行固定?此处的规则取决于您调用的内容,因此,在没有具体示例的情况下,只能给出模糊的建议,但是: 如果您通过p/Invoke调用的方法仅在p/Invoke调用期间使用指针,那么:在几乎所有情况下,您都可以传递一个隐式指针,或者在调用周围使用
fixed
(即,如果p/Invoke签名仅声明SomeStruct*
或IntPtr
)将正常工作
如果您通过p/Invoke调用的方法在指针返回之前存储了指针,然后期望该指针有意义(可能对于基于回调的异步/完成API),那么在这种情况下,您需要确保数据不会移动:
- 对于非托管内存,例如来自
:无需任何操作AllocHGlobal
- 对于堆栈下部的内存(即堆栈帧在此期间不会被重用的位置):无需任何操作
- (如果您将堆栈内存用于P/Invoke,但无法满足该条件:您犯了严重的设计错误)
- 对于托管内存(堆上的对象等);这就是乐趣的开始;请注意,.NET5引入了“固定对象堆”(通常用于P/Invoke的数组),但除此之外:您需要手动固定对象堆