C# 垃圾回收
垃圾回收
.NET 的垃圾回收器管理应用程序的内存分配和释放。 每当有对象新建时,公共语言运行时都会从托管堆为对象分配内存。 只要托管堆中有地址空间,运行时就会继续为新对象分配空间。 不过,内存并不是无限的。 垃圾回收器最终必须执行垃圾回收来释放一些内存。 垃圾回收器的优化引擎会根据所执行的分配来确定执行回收的最佳时机。 执行回收时,垃圾回收器会在托管堆中检查应用程序不再使用的对象,然后执行必要的操作来回收其内存。
垃圾回收的条件
当满足以下条件之一时将发生垃圾回收:
- 系统具有低的物理内存。 这是通过 OS 的内存不足通知或主机指示的内存不足检测出来。
- 由托管堆上已分配的对象使用的内存超出了可接受的阈值。 随着进程的运行,此阈值会不断地进行调整。
- 调用 GC.Collect 方法。 几乎在所有情况下,你都不必调用此方法,因为垃圾回收器会持续运行。 此方法主要用于特殊情况和测试。
代数
堆按代进行组织,因此它可以处理长生存期的对象和短生存期的对象。 垃圾回收主要在回收通常只占用一小部分堆的短生存期对象时发生。 堆上的对象有三代:
- 第 0 代。 这是最年轻的代,其中包含短生存期对象。 短生存期对象的一个示例是临时变量。 垃圾回收最常发生在此代中。
新分配的对象构成新一代对象,并隐式地成为第 0 代集合。 但是,如果它们是大型对象,它们将延续到第 2 代集合中的大型对象堆。
大多数对象通过第 0 代中的垃圾回收进行回收,不会保留到下一代。 - 第 1 代。 这一代包含短生存期对象并用作短生存期对象和长生存期对象之间的缓冲区。
- 第 2 代。 这一代包含长生存期对象。 长生存期对象的一个示例是服务器应用程序中的一个包含在进程期间处于活动状态的静态数据的对象。
当条件得到满足时,垃圾回收将在特定代上发生。 回收某个代意味着回收此代中的对象及其所有更年轻的代。 第 2 代垃圾回收也称为完整垃圾回收,因为它回收所有代上的所有对象(即,托管堆中的所有对象)。
弱引用
如果应用程序的代码可以访问一个正由该程序使用的对象,垃圾回收器就不能回收该对象, 那么,就认为应用程序对该对象具有强引用。
弱引用允许应用程序访问对象,同时也允许垃圾回收器收集相应的对象。 如果不存在强引用,则弱引用的有限期只限于收集对象前的一个不确定的时间段。 使用弱引用时,应用程序仍可对该对象进行强引用,这样做可防止该对象被收集。 但始终存在这样的风险:垃圾回收器在重新建立强引用之前先处理该对象。
若要对某对象建立弱引用,请使用要跟踪的对象实例创建 WeakReference。 然后将 Target 属性设置为该对象,将该对象的原始引用设置为 null。 有关代码示例,请参阅类库中的 WeakReference。
参考:https://docs.microsoft.com/zh-cn/dotnet/standard/garbage-collection/memory-management-and-gc