.NET 6 WinForms应用内存长期未释放问题排查求助
针对你遇到的.NET 6 WinForms应用内存攀升、关闭窗体后堆内存延迟下降的问题,核心原因可以归结为以下几点:
.NET GC的延迟回收与触发机制
.NET垃圾回收器(GC)不会在对象刚变为不可达时立即执行回收操作,尤其是Full GC(负责回收第2代堆和大对象堆)。Full GC的触发阈值较高,通常只有当应用内存压力达到预设值、系统内存紧张,或者应用进入长期闲置状态时,CLR才会触发Full GC。你关闭窗体后,虽然窗体相关对象已不可达,但GC可能还未满足触发Full GC的条件,因此堆内存不会立即下降;而闲置15-30分钟后,CLR在后台执行Full GC,才会彻底回收这些对象。大对象堆(LOH)的特殊回收逻辑
你每次加载的300MB数据,其中大部分对象会被分配到大对象堆(LOH,.NET中默认大于85KB的对象进入LOH)。LOH的回收规则比普通堆更严格:只有Full GC会处理LOH,且默认不会对LOH进行内存压缩。这意味着LOH中的未使用对象不会被及时回收,必须等到Full GC触发后才能被清理。闲置时的Full GC正好触发了LOH的回收,因此内存会下降。CLR的内存保留策略
GC完成回收后,不会立即将所有空闲内存归还给操作系统,而是会保留一部分作为预留内存,用于后续对象分配,避免频繁向操作系统申请内存的开销。只有当应用长期闲置,CLR判断后续不会有大量内存需求时,才会将多余的内存释放给操作系统,这时候你看到的整体内存占用才会明显下降。WinForms窗体的潜在资源引用残留
虽然窗体已关闭,但可能存在未取消的事件订阅(比如静态事件持有窗体对象引用)、未释放的非托管资源(如控件句柄、第三方组件资源),这些残留引用会让GC暂时无法标记对象为不可达。随着时间推移,WinForms的后台资源清理线程完成工作,或者GC进行更彻底的根引用扫描,这些对象才会被标记为可回收,最终在Full GC时被清理。
内容的提问来源于stack exchange,提问作者Dan Friedman

