You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C# GC是否会移动静态类方法?委托传C++ DLL x86崩溃如何解决

首先纠正你的初始猜测错误

GC 不会移动托管方法的代码:托管方法编译后的指令存放在 CLR 管理的代码段区域,不属于 GC 托管堆的可移动对象范畴,你遇到的崩溃和 GC 移动对象没有任何关系。
另外你已经将委托实例存储在静态字段delegateInstance中,已经完成了委托的保活,避免了委托被 GC 回收导致非托管侧调用野指针的问题。


崩溃的核心原因:调用约定不匹配

你遇到的 x86 崩溃、x64 正常的现象,完全是调用约定差异导致的:

  1. 为什么添加UnmanagedFunctionPointer特性后就可以正常运行
    x86 环境下,未添加[UnmanagedFunctionPointer]特性时,委托转非托管函数指针的默认调用约定是CallingConvention.StdCall,而你的 C++ 代码中函数指针的默认调用约定是Cdecl,同时你在[DllImport]中也指定了CallingConvention.Cdecl。
    两边调用约定不一致会直接导致栈帧平衡被破坏,程序运行时直接静默崩溃。添加[UnmanagedFunctionPointer(CallingConvention.Cdecl)]后,委托的非托管调用约定和 C++ 侧对齐,问题自然解决。
  2. 为什么 x64 环境下不加特性也能正常运行
    Windows 平台的 x64 架构有统一的标准调用约定,所有CallingConvention枚举的配置都会被 CLR 忽略,无论你指定StdCall还是Cdecl,最终都会使用同一份 x64 调用约定,因此哪怕你不添加该特性,两边调用约定也是对齐的,不会出现崩溃。

额外注意事项

如果你的 C++ 侧是异步回调(即foo函数接收函数指针后立刻返回,后续在其他时机主动调用回调),需要确保委托实例在整个回调可用周期内都被强引用保活,避免 GC 回收委托后非托管侧调用野指针。你当前将委托存在静态字段的方案可以满足这个要求。


内容的提问来源于stack exchange,提问作者elo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.29 19:36:01