将C# Mono嵌入MSVC C++项目时出现大量内存泄漏求助
我正尝试将C# Mono嵌入MSVC C++项目中,但检测到大量(可能数百处)内存泄漏。通过运行_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);排查后,发现这些泄漏均来自Mono。我的代码仅执行了Mono的初始化与卸载操作:
mono_set_assemblies_path("../lib/mono"); MonoDomain* rootDomain = mono_jit_init("TestRuntime"); if (rootDomain == nullptr) { throw("Failed to initialize Mono"); return 0; } // Create a new app domain // @param domainName: Name of the domain // @param configFile: Config file to use char domainName[] = "TestRuntime"; MonoDomain* appDomain = mono_domain_create_appdomain(domainName, nullptr); // Set the app domain as the active domain // @param domain: The domain to set as active // @param force: If true, the domain is set as the active domain even if it is not the root domain mono_domain_set(appDomain, true); //////MonoAssembly* CoreAssembly = loadCSharpAssembly("../Extern/Scripts/ScriptCore.dll"); //////MonoImage* assemblyImage = mono_assembly_get_image(CoreAssembly); mono_domain_set(mono_get_root_domain(), false); mono_domain_unload(appDomain); appDomain = nullptr; mono_jit_cleanup(rootDomain); rootDomain = nullptr;
该问题最初出现在我的主游戏项目中,我尝试从零搭建测试项目排查,但仍存在内存泄漏。两次均参考Cherno的方案链接Mono,且已复制lib、include等必要文件夹,但问题未解决。请问这是配置问题还是其他原因?
问题分析与解决办法
Mono内存管理特性导致的误报
Mono自身有独立的GC和内存池机制,_CrtSetDbgFlag仅检测CRT原生堆的分配,而Mono内部很多资源是在托管堆或自管理内存池中,不会通过CRT分配。部分初始化时的全局资源Mono会保留用于后续复用,这类"泄漏"并非真的内存泄漏,只是工具误报。优化AppDomain卸载流程
当前卸载步骤缺少强制GC的环节,可能导致托管资源未被及时回收,进而引发原生层的残留泄漏。修改后的卸载流程如下:
// 切换回根域(确保当前无AppDomain内的活跃操作) mono_domain_set(mono_get_root_domain(), true); // 强制触发Mono GC,回收AppDomain内的托管资源 mono_gc_collect(mono_gc_max_generation()); // 卸载AppDomain mono_domain_unload(appDomain); appDomain = nullptr; // 再次触发GC清理可能残留的原生关联资源 mono_gc_collect(mono_gc_max_generation()); // 完成JIT清理 mono_jit_cleanup(rootDomain); rootDomain = nullptr;
- CRT与Mono分配器的冲突
如果Mono使用的内存分配器和MSVC CRT不一致,_CrtSetDbgFlag会误报泄漏。可以:
- 若自行编译Mono,指定使用CRT分配器编译;
- 用
_CrtSetReportMode过滤掉Mono模块的泄漏报告,避免干扰:_CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE); _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDOUT); // 过滤Mono相关的分配日志
版本差异问题
Cherno教程使用的Mono版本可能和你当前使用的版本存在差异,不同版本的Mono在资源释放逻辑上有变化。建议核对教程中的Mono版本,使用相同版本测试。补充AppDomain配置文件
创建AppDomain时传入nullptr作为配置文件,部分Mono版本会因缺少必要配置导致资源无法正确释放。可以创建一个简单的app.config文件:
<configuration> <runtime> <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> <dependentAssembly> <assemblyIdentity name="mscorlib" publicKeyToken="b77a5c561934e089" culture="neutral" /> <bindingRedirect oldVersion="0.0.0.0-4.0.0.0" newVersion="4.0.0.0" /> </dependentAssembly> </assemblyBinding> </runtime> </configuration>
然后修改AppDomain创建代码:
MonoDomain* appDomain = mono_domain_create_appdomain(domainName, "app.config");
内容的提问来源于stack exchange,提问作者PsychoPlayce -_-

