理解C#中的挂起引用

本文关键字:挂起 引用 理解 | 更新日期: 2023-09-27 18:26:20

我正在努力教育自己,在像C#这样的垃圾收集语言中,泄漏或悬挂引用是如何发生的。我在网上发现了一个虚构的例子,我修改并观察到(通过任务管理器),它在每一次按键时都是安静的"泄漏"。

来源:

using System;
using System.Collections.Generic;
namespace ConsoleApplication1
{
    public class Something
    {
        int[] things;
        public Something() {
            things = new int[10000000];
            Random rnd = new Random();
            for (int i = 0; i < things.Length; ++i) {
                things[i] = rnd.Next();
            }
        }
    }
    static public class SomethingFactory
    {
        public static Something CreateSomething() {
            Something something = new Something();
            return something;
        }
    }
    class Program
    {
        static void Main(string[] args) {
            while (true) {
                Console.ReadKey();
                Console.WriteLine("Creating...");
                Something s = SomethingFactory.CreateSomething();
            }
        }
    }
}

为什么会出现悬空引用?乍一看,Something s似乎是在while (true)的范围内实例化的,在块结束后,不应该存在对该项的其他引用。然而,随着每一次按键,我看到应用程序的内存使用量都会增加约40mb,而且似乎从未下降。

理解C#中的挂起引用

您没有做任何异常的事情。在您的样本中,GC可以回收大量报告为正在使用的内存。但是,请记住,当您在任务管理器中观察内存时,您看到的是进程内存。在托管应用程序中,CLR充当代表应用程序的内存管理器。它在进程级别分配和释放内存。

其工作方式是分配chuck内存来存储托管堆上的对象。当物体数量下降时,这些卡盘最终将再次释放到操作系统。需要记住的是,CLR在这方面尽量聪明,所以它不会在每次托管堆更改时都进行分配和释放。因此,通过查看进程级别的内存使用情况,很难理解托管内存是如何使用的。

您看到的很可能是内存被分配而没有释放,因为CLR还没有任何理由释放这些chuck。