C# GC是否会移动静态类方法?委托传C++ DLL x86崩溃如何解决
首先纠正你的初始猜测错误
GC 不会移动托管方法的代码:托管方法编译后的指令存放在 CLR 管理的代码段区域,不属于 GC 托管堆的可移动对象范畴,你遇到的崩溃和 GC 移动对象没有任何关系。
另外你已经将委托实例存储在静态字段delegateInstance中,已经完成了委托的保活,避免了委托被 GC 回收导致非托管侧调用野指针的问题。
崩溃的核心原因:调用约定不匹配
你遇到的 x86 崩溃、x64 正常的现象,完全是调用约定差异导致的:
- 为什么添加
UnmanagedFunctionPointer特性后就可以正常运行
x86 环境下,未添加[UnmanagedFunctionPointer]特性时,委托转非托管函数指针的默认调用约定是CallingConvention.StdCall,而你的 C++ 代码中函数指针的默认调用约定是Cdecl,同时你在[DllImport]中也指定了CallingConvention.Cdecl。
两边调用约定不一致会直接导致栈帧平衡被破坏,程序运行时直接静默崩溃。添加[UnmanagedFunctionPointer(CallingConvention.Cdecl)]后,委托的非托管调用约定和 C++ 侧对齐,问题自然解决。 - 为什么 x64 环境下不加特性也能正常运行
Windows 平台的 x64 架构有统一的标准调用约定,所有CallingConvention枚举的配置都会被 CLR 忽略,无论你指定StdCall还是Cdecl,最终都会使用同一份 x64 调用约定,因此哪怕你不添加该特性,两边调用约定也是对齐的,不会出现崩溃。
额外注意事项
如果你的 C++ 侧是异步回调(即foo函数接收函数指针后立刻返回,后续在其他时机主动调用回调),需要确保委托实例在整个回调可用周期内都被强引用保活,避免 GC 回收委托后非托管侧调用野指针。你当前将委托存在静态字段的方案可以满足这个要求。
内容的提问来源于stack exchange,提问作者elo
相关产品推荐
相关产品推荐

