Meh*_*dad 22 .net c# pinvoke unmanaged managed
我知道CLR需要在某些情况下进行编组,但是让我说我有:
using System.Runtime.InteropServices;
using System.Security;
[SuppressUnmanagedCodeSecurity]
static class Program
{
[DllImport("kernel32.dll", SetLastError = false)]
static extern int GetVersion();
static void Main()
{
for (; ; )
GetVersion();
}
}
Run Code Online (Sandbox Code Playgroud)
当我用调试器进入这个程序时,我总是看到:

鉴于没有需要完成的编组(对吗?),有人可以解释一下这种"托管到本地的过渡"中实际发生了什么,以及为什么有必要?
usr*_*usr 11
首先需要设置调用堆栈,以便可以发生STDCALL.这是Win32的调用约定.
接下来,运行时将推送一个所谓的执行帧.有许多不同类型的框架:安全断言,GC保护区域,本机代码调用,......
运行时使用这样的帧来跟踪当前正在运行的本机代码.这对潜在的并发垃圾收集以及其他可能的东西都有影响.它还有助于调试器.
所以实际上并没有发生太多事情.这是一个非常苗条的代码路径.
除了负责为您转换参数和确定调用约定的封送层之外,运行时还需要做一些其他的事情来保持内部状态的一致性。
需要检查安全上下文,以确保允许调用代码访问本机方法。当前托管堆栈帧需要保存,以便运行时可以为调试和异常处理(更不用说调用托管回调的本机代码)进行堆栈回溯。需要设置内部状态位以指示我们当前正在运行本机代码。
此外,可能需要保存寄存器,这取决于需要跟踪的内容以及调用约定保证可以恢复的内容。寄存器(本地)中的 GC 根可能需要以某种方式进行标记,以便它们不会在本机方法期间被垃圾收集。
所以主要是堆栈处理和类型编组,还有一些安全性的东西。虽然它不是大量的东西,但它将代表调用较小的本地方法的重大障碍。例如,尝试对优化的数学库进行 P/Invoke 很少会带来性能优势,因为开销足以抵消任何潜在的好处。此处讨论了一些性能分析结果。
我意识到这个问题已经得到解答,但令我惊讶的是没有人建议您在调试窗口中显示外部代码。如果右键单击该[Native to Managed Transition]行并勾选该Show External Code选项,您将准确地看到在转换中调用了哪些 .NET 方法。这可能会给你一个更好的主意。这是一个例子:

| 归档时间: |
|
| 查看次数: |
4846 次 |
| 最近记录: |