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

将C# Mono嵌入MSVC 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等必要文件夹,但问题未解决。请问这是配置问题还是其他原因?


问题分析与解决办法

  1. Mono内存管理特性导致的误报
    Mono自身有独立的GC和内存池机制,_CrtSetDbgFlag仅检测CRT原生堆的分配,而Mono内部很多资源是在托管堆或自管理内存池中,不会通过CRT分配。部分初始化时的全局资源Mono会保留用于后续复用,这类"泄漏"并非真的内存泄漏,只是工具误报。

  2. 优化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;
  1. CRT与Mono分配器的冲突
    如果Mono使用的内存分配器和MSVC CRT不一致,_CrtSetDbgFlag会误报泄漏。可以:
  • 若自行编译Mono,指定使用CRT分配器编译;
  • 用_CrtSetReportMode过滤掉Mono模块的泄漏报告,避免干扰:
    _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
    _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDOUT);
    // 过滤Mono相关的分配日志
    
  1. 版本差异问题
    Cherno教程使用的Mono版本可能和你当前使用的版本存在差异,不同版本的Mono在资源释放逻辑上有变化。建议核对教程中的Mono版本,使用相同版本测试。

  2. 补充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 -_-

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 06:43:16