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

Linux Docker环境下dotnet publish内存占用过高问题排查求助

问题描述

我们正通过Dockerfile构建.NET Core 6.0应用,使用的构建命令如下:

DOCKER_BUILDKIT=1 docker buildx build --output type=image,oci-mediatypes=true --provenance=false -t 734656666.dkr.ecr.ap-south-1.amazonaws.com/abcwbw-stg:develop-7700 -t 726616043643.dkr.ecr.ap-south-1.amazonaws.com/abcwbw-stg:develop --progress=plain --build-arg Configuration=Staging --build-arg S3BucketKey=stc-staging.acdn.com/ --build-arg BranchName=develop --build-arg GitToken=**** --build-arg ServiceName=null  --cache-from type=registry,ref=334533333.dkr.ecr.ap-south-1.amazonaws.com/abcwbw-build-cache:abcwbw-stg-develop -f Dockerfile .

Dockerfile中包含的publish命令:

dotnet publish -c Staging -o out -p:CIBuild=True -p:RunSonarAnalysis=false -p:RunCodeAnalysis=false -r linux-x64 --no-self-contained --no-restore proj/proj.UI.csproj

在配备64GB内存的Ubuntu机器上执行构建时,publish过程内存逐渐耗尽,最终触发内存不足错误,已通过htop观测到此现象。

需要解决以下问题:

  1. 当前publish命令是否存在问题?
  2. 如何调试内存占用问题?
  3. 是否可以获取堆转储并进行分析?

一、当前publish命令是否存在问题?

从参数本身来看,这条dotnet publish命令没有明显语法错误:

  • -c Staging对应构建配置,符合预期;
  • -p:RunSonarAnalysis=false和-p:RunCodeAnalysis=false已禁用代码分析,排除了这类任务的内存开销;
  • --no-self-contained和--no-restore是CI构建的常规优化参数,不会直接引发内存泄漏;
  • -r linux-x64仅指定目标运行时,本身不会导致内存异常。

但要注意:如果项目存在大量依赖包、大型嵌入资源,或是引用了有内存泄漏问题的自定义MSBuild任务,即使命令参数正确,也可能在publish阶段出现内存占用过高的情况。另外,部分.NET 6 SDK旧补丁版本存在MSBuild内存泄漏的已知bug,建议先排查SDK版本。

二、如何调试内存占用问题?

按以下步骤逐步排查:

  • 升级.NET 6 SDK到最新补丁版本:微软在后续补丁中修复了多个MSBuild相关的内存泄漏问题,优先升级到最新6.x版本验证是否解决问题。
  • 启用详细构建日志:在dotnet publish命令中添加-v diag参数,输出完整的MSBuild执行日志,定位内存暴涨的具体阶段(比如依赖还原、编译、发布打包哪个环节)。
  • 排除Docker环境干扰:直接在Ubuntu主机上执行dotnet publish命令(跳过Docker构建),观察是否同样出现内存耗尽,判断问题源于项目本身还是Docker构建环境。
  • 限制Docker构建资源:在docker buildx build命令中添加--memory 48g参数,限制构建容器的内存上限,结合--progress=plain的输出日志,确定OOM发生的具体步骤。
  • 检查项目结构:排查是否存在大量NuGet包引用、大型静态文件嵌入、多项目循环引用,或是自定义MSBuild任务存在内存泄漏。

三、是否可以获取堆转储并进行分析?

可以获取堆转储并分析内存占用情况,分两种场景处理:

1. 主机直接执行publish时获取堆转储

  • 安装dotnet-dump工具:
    dotnet tool install --global dotnet-dump
    
  • 找到dotnet publish进程的PID:
    ps aux | grep dotnet
    
  • 捕获堆转储文件:
    dotnet-dump collect -p <PID>
    

2. Docker构建过程中获取堆转储

Docker构建容器默认限制调试权限,需调整配置:

  • 修改Dockerfile,在publish步骤前安装dotnet-dump工具,同时后台监控进程;或在docker buildx build命令中添加--cap-add SYS_PTRACE参数,赋予容器调试权限。
  • 更简便的方式是将publish步骤抽离到主机执行,完成后将发布产物复制到Docker镜像中,直接在主机环境捕获堆转储。

堆转储分析

  • 命令行分析:
    dotnet-dump analyze <dump-file-path>
    
    在分析环境中,用dumpheap查看所有托管对象,gcroot查找对象引用链,定位内存占用最高的对象或泄漏点。
  • 可视化分析:将堆转储文件导入Visual Studio或JetBrains Rider等IDE,通过内存分析工具直观查看内存分配情况、对象引用关系。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 08:42:48