C# 为什么GC不收集未使用的对象

C# 为什么GC不收集未使用的对象,c#,garbage-collection,c#-6.0,C#,Garbage Collection,C# 6.0,我试图理解当一个对象不再被使用时GC是如何工作的,我的测试是对该对象不做任何处理(使用后),但它不工作,该对象的析构函数从未被调用 我创建了一个示例程序,试图等待对象被销毁,但运行4小时后什么也没有发生 注意:我知道如果我将对象设置为null,GC将收集它,但我只想看到GC本身收集对象的“正常”方式 using System; using System.Collections.Generic; using System.IO; using System.Threading; using Syst

我试图理解当一个对象不再被使用时GC是如何工作的,我的测试是对该对象不做任何处理(使用后),但它不工作,该对象的析构函数从未被调用

我创建了一个示例程序,试图等待对象被销毁,但运行4小时后什么也没有发生

注意:我知道如果我将对象设置为null,GC将收集它,但我只想看到GC本身收集对象的“正常”方式

using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApplication1
{
    internal class Program
    {
        private const string FilePath = @"C:\objLifeCycle.txt";

        private static void Main(string[] args)
        {
            var result = GetList();
            Console.WriteLine("Results received! Object Id: [{0}] time: [{1}]", result.ObjId, DateTime.Now);

            //result = null;

            Task.Factory.StartNew(() =>
            {
                while (true)
                {
                    Thread.Sleep(2000);
                    Console.WriteLine("...");
                    GC.Collect();
                }
            });

            Console.ReadKey();
        }

        private static LinkList GetList()
        {
            return new LinkList(FilePath) { "link1", "link2", "link3" };
        }
    }
}

internal class LinkList : List<string>
{
    internal string ObjId { get; set; }

    internal string FilePath { get; set; }

    internal LinkList(string filePath)
    {
        ObjId = Guid.NewGuid().ToString();
        FilePath = filePath;

        WriteFile($"Object LinkList with Id [{ObjId}] has been created at [{DateTime.Now}]");
    }

    ~LinkList()
    {
        WriteFile($"Object LinkList with Id [{ObjId}] has been destroyed at [{DateTime.Now}]");

        Environment.Exit(0);
    }

    private void WriteFile(string line)
    {
        var sw = new StreamWriter(FilePath, true);
        sw.WriteLine(line);
        sw.Close();
    }
}
使用系统;
使用System.Collections.Generic;
使用System.IO;
使用系统线程;
使用System.Threading.Tasks;
命名空间控制台应用程序1
{
内部课程计划
{
private const string FilePath=@“C:\objLifeCycle.txt”;
私有静态void Main(字符串[]args)
{
var result=GetList();
WriteLine(“收到的结果!对象Id:[{0}]时间:[{1}]”,result.ObjId,DateTime.Now);
//结果=空;
Task.Factory.StartNew(()=>
{
while(true)
{
《睡眠》(2000年);
Console.WriteLine(“…”);
GC.Collect();
}
});
Console.ReadKey();
}
私有静态链接列表GetList()
{
返回新的链接列表(文件路径){“link1”、“link2”、“link3”};
}
}
}
内部类链接列表:列表
{
内部字符串ObjId{get;set;}
内部字符串文件路径{get;set;}
内部链接列表(字符串文件路径)
{
ObjId=Guid.NewGuid().ToString();
FilePath=FilePath;
WriteFile($“Id为[{ObjId}]的对象链接列表已在[{DateTime.Now}]创建”);
}
~LinkList()
{
WriteFile($“Id为[{ObjId}]的对象链接列表已在[{DateTime.Now}]销毁”);
环境。退出(0);
}
私有void WriteFile(字符串行)
{
var sw=新的StreamWriter(FilePath,true);
西南写入线(行);
sw.Close();
}
}

GC不会以确定的方式收集免费资源。程序应该需要内存来请求资源。如果有足够的资源,GC将不会收集任何东西,因为没有必要。GC也只能在程序“空闲”状态下收集内存

我强烈建议您阅读:

正如您在文档中测试和看到的,即使调用

除此之外,实际上您需要了解,根据平台和CLR实现,有一些GC风格


出于测试目的,您可以使用来增加收集内存的需要。

GC不会以确定的方式收集空闲资源。程序应该需要内存来请求资源。如果有足够的资源,GC将不会收集任何东西,因为没有必要。GC也只能在程序“空闲”状态下收集内存

我强烈建议您阅读:

正如您在文档中测试和看到的,即使调用

除此之外,实际上您需要了解,根据平台和CLR实现,有一些GC风格

出于测试目的,您可以使用GC收集对象来增加收集内存的需要,但仅在释放模式下

在调试模式下,变量
result
只要在作用域中就存在,即使您不使用它,这样调试器就可以不断向您显示其值。但这也意味着该对象不能被垃圾收集

在发布模式下,.Net足够智能,可以实现不再使用该对象,因此它可以进行垃圾收集。当GC被调用时(在您的例子中,通过调用
GC.Collect()
),它将收集它。

GC将收集对象,但仅在释放模式下

在调试模式下,变量
result
只要在作用域中就存在,即使您不使用它,这样调试器就可以不断向您显示其值。但这也意味着该对象不能被垃圾收集


在发布模式下,.Net足够智能,可以实现不再使用该对象,因此它可以进行垃圾收集。当GC被调用时(在您的例子中,显式地调用
GC.Collect()
),它将收集它。

通过向LinkList类添加析构函数,实例化的对象将立即升级到gen1堆。Gen1堆收集的执行频率不如gen0堆收集的执行频率高,并且由于您的可用内存可能很充足,因此此应用程序很可能永远不会执行此类收集。通过向链接列表类添加析构函数,实例化的对象会立即升级到Gen1堆。Gen1堆收集的执行频率不如gen0堆收集的执行频率高,而且由于您可能有足够的可用内存,因此此应用程序很可能永远不会执行此类收集。问题中的程序显式调用了收集所有代的
GC.Collect()
。所以这与斯维克无关,但事实上是这样。不确定地调用GC.Collection会启动一个集合,但在所示的示例中,即使发生了一个集合,如果所讨论的变量实际上要被收集,也是不确定的。允许GC得出结论,不再使用该变量,因此可以进行清理,但不需要这样做(无论代码是否在发布/调试版本中编译)我用补充信息更新了我的答案,解释了为什么GC.Collect并不意味着强制垃圾collection@Servy我认为称之为不确定性,虽然从技术上讲是正确的,但令人困惑。在具有任何给定设置的任何给定实现上,它很可能是确定性的。所以我认为更好的方法是说它是