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

C#强制GC后死对象未回收的内存诊断问题咨询

C# GC与终结器相关问题解答

问题1:为何内存占用未回落至初始大小?第二次快照从114MB升至118MB是否因死对象?第三次快照为何升至125MB而非回落?

  • 内存未回落初始大小:带终结器的对象不会在单次GC.Collect()后直接回收。这类对象被标记为可回收后,会被移入终结队列(Finalization Queue),需等待终结器线程执行其终结方法,之后还要再经历一次GC才会真正释放内存。第一次强制GC仅完成标记和入队操作,对象仍占用内存。
  • 第二次快照升至118MB:正是新增的10万个DummyPojo对象的内存占用,叠加ASP.NET Core Web API运行时本身的基础内存(114MB)导致的。
  • 第三次快照升至125MB:原因有两点:一是GC处理终结器流程时会分配内部跟踪用的数据结构(如队列条目),终结器线程运行也会产生临时内存开销;二是GC回收后不会立即将内存归还操作系统,会保留部分作为托管堆预留内存供后续分配使用,同时Web API运行时本身可能也会产生一些非托管内存或临时对象的分配,最终导致进程内存占用进一步上升。

问题2:内存持续增长,但快照差异显示绿色(表示内存减少),为何出现相反情况?

  • 两者统计的内存范围不同:Visual Studio内存快照的差异对比仅统计托管堆中存活对象的内存大小,绿色标识代表托管堆内部分对象被回收;而你观察到的“内存持续增长”是进程的私有工作集(包含托管堆、非托管内存、JIT编译代码、操作系统分配的资源等)。当托管堆内存减少的同时,非托管内存(如终结器线程开销、Web API非托管组件)或GC预留堆内存增加时,就会出现进程整体内存上升但快照差异显示内存减少的矛盾情况。

问题3:第三次快照中仍存在DummyPojo死对象,强制GC为何未回收?

  • 带终结器的对象回收是两步式流程:
    1. 第一次GC标记对象为可回收,将其移入终结队列,此时对象仍处于“存活”状态(因为终结器尚未执行);
    2. 终结器线程执行完对象的终结方法后,对象会被移入待回收队列(Freachable Queue),需等待第二次GC才能真正被回收。
  • 你仅调用了一次GC.Collect(),此时要么终结器线程尚未完成所有DummyPojo对象的终结方法执行,要么执行完后还未触发第二次GC,因此对象仍会留在内存中。另外需排查是否存在其他根引用(如静态变量、事件订阅)导致DummyPojo对象未被标记为可回收。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 18:40:14