C#通过DllImport传数组到C++ DLL删除时报System.AccessViolationException
问题根因与修复方案
触发System.AccessViolationException的核心原因是C++侧尝试删除的指针不属于当前模块CRT堆的合法可释放范围,可按以下方向逐一排查修复:
- 内存分配释放一致性校验:所有需要C侧
delete释放的Game实例,必须由当前C DLL导出的分配接口(如CreateGame()这类自定义导出函数)创建,确保内存分配和释放处于同一个CRT堆中。如果Game实例是C#侧托管内存分配、或是其他模块分配的内存,直接用当前DLL的delete释放必然触发访问越界。 - DllImport签名匹配校验:C#侧的函数声明必须和C++导出完全匹配,尤其注意调用约定和数组封送规则,参考正确声明如下:
C++默认导出的函数调用约定为Cdecl,如果C#侧未显式指定默认使用Stdcall,会导致参数压栈错乱,拿到的// 注意调整CallingConvention和DLL文件名与实际情况一致 [DllImport("你的DLL名称.dll", CallingConvention = CallingConvention.Cdecl)] public static extern void empty([In] IntPtr[] gamePtrArray, int index);x[y]本身就是非法野指针。 - 传递类型正确性校验:C参数
Game* x[]本质是Game**类型,对应C#侧必须传递IntPtr数组(每个元素为C侧分配的Game实例指针),如果直接传递Game结构体数组,x[y]会被解析为结构体值而非合法指针,执行delete必然崩溃。 - 下标合法性校验:传入的
y值不能超过数组x的有效下标范围,越界访问拿到的非法指针执行释放操作也会触发访问异常。 - 重复释放校验:确认
x[y]对应的指针没有被提前释放过,建议每次释放后将对应位置的指针置为nullptr,避免二次释放问题。 - 额外说明:你当前C代码中的
try catch只能捕获标准C异常,无法捕获访问越界这类结构化异常,如果需要在C++侧拦截这类错误避免进程直接崩溃,需要给DLL开启/EHa结构化异常处理编译选项,但该操作无法解决根本问题,仅能做兜底容错。
内容的提问来源于stack exchange,提问作者Literal Garbage
相关产品推荐
相关产品推荐

