理解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,而且似乎从未下降。
您没有做任何异常的事情。在您的样本中,GC可以回收大量报告为正在使用的内存。但是,请记住,当您在任务管理器中观察内存时,您看到的是进程内存。在托管应用程序中,CLR充当代表应用程序的内存管理器。它在进程级别分配和释放内存。
其工作方式是分配chuck内存来存储托管堆上的对象。当物体数量下降时,这些卡盘最终将再次释放到操作系统。需要记住的是,CLR在这方面尽量聪明,所以它不会在每次托管堆更改时都进行分配和释放。因此,通过查看进程级别的内存使用情况,很难理解托管内存是如何使用的。
您看到的很可能是内存被分配而没有释放,因为CLR还没有任何理由释放这些chuck。