.NET Core 6中用Marshal.AllocHGlobal替代VirtualAlloc遇内存异常咨询
问题
从.NET Framework升级至.NET 6的遗留非托管代码(含unsafe、IntPtr),原代码多次调用kernel32.dll的VirtualAlloc方法分配非托管IntPtr。发布到Ubuntu Linux平台运行时,出现无法加载kernel32.dll的异常:
An unhandled exception was thrown by the application. 2022-11-03T10:55:31.08+0200 [APP/PROC/WEB/0] OUT System.AggregateException: One or more errors occurred. (Unable to load shared library 'kernel32.dll' or one of its dependencies. In order to help diagnose loading problems, consider setting the LD_DEBUG environment variable: libkernel32.dll: cannot open shared object file: No such file or directory)
推测kernel32.dll无法作为跨平台DLL在.NET Core中使用,尝试改用Marshal.AllocHGlobal()替代后,出现以下异常:
attempted to read write protected memory
原因是应用中的部分IntPtr大小已损坏。请问Marshal.AllocHGlobal()与VirtualAlloc()功能是否完全相同?是否必须修改应用中的变量大小才能使用前者替代后者?
回答
功能不完全相同
VirtualAlloc是Windows专属的内存分配API,支持多种内存分配类型(预留、提交等)、内存保护属性(只读、读写、执行等),还能指定内存地址对齐等高级操作。Marshal.AllocHGlobal是.NET提供的跨平台内存分配方法,底层会调用对应平台的基础分配API(Windows用LocalAlloc,Linux用malloc),仅提供基础堆内存分配能力,不支持VirtualAlloc的高级内存管理特性。
内存保护属性不匹配是报错核心原因
你遇到的attempted to read write protected memory异常,大概率是因为原代码调用VirtualAlloc时指定了特定内存保护属性(比如允许执行),但Marshal.AllocHGlobal分配的内存默认只有读写权限。如果后续代码尝试在这块内存中执行指令,就会触发内存保护异常。无需修改变量大小,但需适配内存属性与分配逻辑
IntPtr的大小会自动适配平台(32位系统4字节,64位系统8字节),不需要手动修改。但要调整内存分配逻辑:- 若代码需要执行分配内存中的指令,Linux平台需通过P/Invoke调用
mmap来分配带执行权限的内存; - 若仅需普通读写内存,检查原代码是否依赖
VirtualAlloc的其他特性(如内存预留),如有则替换为对应跨平台实现; - 同步替换内存释放逻辑:原
VirtualFree需换成Marshal.FreeHGlobal(对应AllocHGlobal)或平台专属释放API(如Linux的munmap)。
- 若代码需要执行分配内存中的指令,Linux平台需通过P/Invoke调用
内容的提问来源于stack exchange,提问作者Hadar
相关产品推荐
相关产品推荐

