gpt4 book ai didi

c# - 用于 P/Invoke 访问的引脚数据

转载 作者:行者123 更新时间:2023-12-01 14:57:01 26 4
gpt4 key购买 nike

我正在使用 P/Invoke 将数据从 C# 代码传递到 C++ 代码,反之亦然。到目前为止,这工作正常。

最近我读了几篇文章(例如 this one )关于固定这些数据的必要性,因为 GC 可能会在 C++ 执行其任务时重新排列或删除它们。

我查阅了一些 Microsoft 文章,但对我而言,它们并不完全清楚何时需要手动完成固定。我明白了this文章以 CLR 确保 GC 收集时不会出现问题的方式出现。它通过固定数据或将它们复制到 GC 不收集的非托管内存中来实现。所以对我来说,这意味着程序员不需要处理固定。 article 中的示例也没有显示任何固定。我仍然不确定我的结论是否正确。

进一步挖掘,我发现了一些关于我在代码中使用的特定数据类型的更多信息:

intlong:按值传递 - 因此不得固定。但是 ref int 呢?

IntPtr:我使用 AllocHGlobal() 在非托管内存中分配空间。 GC 不会触及它。因此无需固定。

byte[]:通过引用传递但自动固定。参见 here : 作为一项优化,仅包含可 blittable 成员的可 blittable 类型和类的数组在编码期间被固定而不是复制。

string:通过引用传递但自动固定。参见 here : 在编码(marshal)对象(例如 String)期间自动执行固定,但是您也可以使用 GCHandle 类手动固定内存。

string[], 'custom struct with strings': 在这里我真的不确定。 “Pinning is automatically performed during marshaling for objects such as String [...]”这句话是否包括字符串数组和自定义结构?

目前我没有固定任何东西,代码工作正常。即使我强制 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 的数组),但除此之外:您需要手动固定

关于c# - 用于 P/Invoke 访问的引脚数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63776096/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com