垃圾回收中的“Memory Pressure”指什么?与代预算超支有何不同?
关于GC中Memory Pressure的详解
刚好对CLR GC这块有不少实践经验,来给你理清楚Memory Pressure到底是什么,以及它和代预算触发GC的区别:
首先先明确你的疑问背景:
我在阅读Tess Ferrandez关于垃圾回收的内容时,看到她提到触发GC的三种原因:
- 分配新对象时达到generation 0预算,新对象会导致预算超支;
- 手动调用
GC.Collect()触发;- 基于Memory Pressure。
我理解前两点,但对第三点的Memory Pressure具体含义有点困惑:原本以为是系统可用内存不足,但系统内存耗尽应该会蓝屏,所以想知道Memory Pressure实际是什么?它和超过代预算的区别在哪里?
什么是Memory Pressure?
这里的Memory Pressure绝对不是指系统层面的内存耗尽到蓝屏那种极端情况,而是CLR感知到的两种内存紧张信号:
- 内部内存压力:当你的应用程序托管堆(尤其是大对象堆LOH)的内存占用已经达到某个临界值,CLR判断如果不回收后续可能会出现分配失败,就会主动触发GC。比如你的程序一直在分配大对象,LOH占用越来越高,哪怕gen0预算还剩很多,CLR也会触发回收。
- 外部内存压力:Windows系统会给运行中的进程发送「低内存通知」——当系统可用物理内存降到某个安全阈值以下时,CLR收到这个信号后,会立刻触发GC来释放尽可能多的内存,降低进程的内存占用,帮系统缓解压力。
简单说,这是CLR的「预警式回收」,在系统或应用内存真的耗尽前就主动行动,避免进程崩溃或者系统进入极端状态。
和「超过代预算」的核心区别
这两种触发逻辑完全是两回事:
- 超过代预算的GC:是CLR的「常规操作」——每一代(gen0、gen1、gen2)都有预设的内存预算(gen0预算最小,因为小对象分配频繁,回收成本极低),当新对象分配导致当前代的内存占用超过预算时,就会触发对应代的回收(通常先回收gen0,必要时连带回收gen1、gen2)。这种触发和系统内存状态无关,纯粹是托管堆内部的「定期清理」。
- Memory Pressure触发的GC:是「非常规应急操作」——它不看当前代的预算有没有超标,而是基于系统内存状态或者托管堆整体负载来触发。比如你的程序很久没触发gen2回收,托管堆占用过大,或者系统突然内存吃紧,CLR会跳过常规的预算检查,直接触发更深度的回收(比如直接回收gen2甚至LOH)。
举个直观的例子:
- 你写了个循环不断创建小字符串,很快gen0的预算就满了,这时候触发的GC就是「超过代预算」的常规回收;
- 你的程序最近没怎么分配新对象,gen0预算还剩一半,但此时系统打开了很多大型软件,内存告急,CLR收到系统的低内存通知,这时候触发的GC就是Memory Pressure导致的。
内容的提问来源于stack exchange,提问作者BanksySan
相关产品推荐
相关产品推荐

