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

为何垃圾回收器(GC)会被触发两次?代码调试疑问咨询

搞懂你的GC触发困惑

先把你的代码贴出来,方便分析:

public static void Main(string[] args) 
{ 
    while (true) 
    { 
        const int size = 2000000; 
        var arr = new int[size]; 
        Thread.Sleep(1000); 
    } 
}

先算个账:你每次创建的int数组是200万元素,每个int占4字节,总大小是8MB——这个尺寸远超CLR默认的大对象堆(LOH)阈值(85KB),所以每个数组都会直接进第2代的LOH,不会走小对象的第0/1代。

第一次GC为啥触发(你已经明白的部分)

第一次循环创建的arr1占了8MB LOH,循环结束后arr1就没引用了,成了垃圾。第二次循环要创建arr2时,CLR一看LOH已经被arr1占满了,没地方放新的8MB数组,直接触发前台GC——把arr1回收掉,腾出空间给arr2。这部分你已经清楚,不多说。

第二次GC的触发原因(你搞不懂的点)

重点来了,第二次GC大概率是后台GC在干活,原因是这样的:

  • .NET的GC有两种模式:前台GC是阻塞式的,回收时会卡住所有用户线程,一般在内存不够用的时候触发;后台GC是异步跑的,只处理第2代(包括LOH),几乎不阻塞你的代码,是CLR用来“闲时维护”内存的机制。
  • 第一次前台GC干完后,CLR会觉得“趁现在系统闲(你代码里正在Sleep),启动后台GC扫扫第2代的垃圾吧”——这时候就会触发第二次GC,也就是你看到的第二个黄色三角。
  • 这次GC不是因为分配失败,而是CLR主动在空闲时清理垃圾,避免后面再分配大对象时又要触发阻塞的前台GC,同时也能减少LOH的内存碎片化(虽然LOH默认不压缩,但后台GC会标记出可用的空闲块)。

当然,如果你的电脑本身内存就很紧张,操作系统给CLR发了“内存不够用”的信号,CLR也可能触发额外的GC,但这种情况不如后台GC常见。

说白了,第二次GC是CLR的“预防性维护”,属于正常操作,不是你的代码有问题~

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 12:14:28