C# 如果我返回新的本地类实例创建的数组,它会被垃圾收集吗?

C# 如果我返回新的本地类实例创建的数组,它会被垃圾收集吗?,c#,arrays,memory,C#,Arrays,Memory,假设一个类实例将构建数组: class FooArrBuilder { public Foo[] FinalResult { get { return arr; } } Foo[] arr; public void BuildArr(); ... } 然后是这样使用的: Foo[] GetFooArr() { var fb = new FooArrBuilder(); fb.BuildArr(); ... return fb.Fi

假设一个类实例将构建数组:

class FooArrBuilder
{
    public Foo[] FinalResult { get { return arr; } }
    Foo[] arr;
    public void BuildArr();
    ...
}
然后是这样使用的:

Foo[] GetFooArr()
{
    var fb = new FooArrBuilder();
    fb.BuildArr();
    ...
    return fb.FinalResult;
}
当数组构建在函数的本地实例中时,是将数组移出构建它的实例,还是将整个实例保存在内存中以包含数组?如果数组是后者的话,我不一定要复制它,但也许我可以把类变成一个结构?感谢您的帮助:)

如果您想在这里详细介绍一下C#的内存模型,它可能也会帮助我避免进一步的混淆


提前谢谢

是的,会的。只要
Foo
类型的数组项不包含对
fooarBuilder
的引用,类实例就不会“拥有”或“包含”数组。它只引用在堆上分配的数组。对该数组的其他引用不会使该类的实例保持活动状态


如果任何其他对象(或堆栈帧)引用该数组,则为该数组分配的堆内存将保持为该数组分配。一旦这些对象被垃圾收集并且堆栈帧被弹出,垃圾收集器将声明为该数组分配的内存。

我想我现在明白了

当FooarBuilder被实例化时,它是在堆上完成的。 堆栈上会放置一个指向它的指针,大小为int。 堆上分配的对象的引用计数增加1

当FooarBuilder实例创建数组时,对数组的处理过程几乎相同;再次使用引用计数1分配堆对象,这次是Foo[]类型。但是,这次没有在堆栈上放置指针-相反,在前面检索到的堆栈指针指向的内存中,Foo[]arr(实际上是指向Foo[]对象的指针)被设置为指向新数组

当我们即将返回时,我们从实例中检索对Foo[]的另一个引用,称为arr。数组的引用计数现在为2。
当函数返回时,对类实例的引用丢失,因此引用计数现在为0。因此,实例被标记为垃圾。当实例稍后(在某个不确定的点)被垃圾收集时,它对数组的引用将丢失-因此数组的引用计数再次为1。

您可能想了解它的工作原理。挑剔-它永远不会被“处理”,因为它没有实现
IDisposable
。你要找的术语是垃圾收集。即使这样,它也只能进行垃圾收集——收集的确切时间是不可确定的。简而言之,您的类和数组都是引用类型。只要一个对象是“可访问的”,即另一个活动对象对它有引用,它也将保持活动状态。因此,只要保留对数组的引用,它就会保持活动状态。如果不保留对创建数组的对象的引用,将来可能会在某个不确定的点收集它,也可能不会。这是一个很好的逐场操作,但我相信垃圾收集器不会计算引用。垃圾收集从根开始,遵循引用并构建活动对象的图形。如果一个对象不能通过这个过程访问,它将被视为垃圾并被回收。它有点复杂(正如@JerryFederspiel提到的)。如果您真的想深入了解幕后的情况,我建议您使用一个关于托管堆和垃圾收集的大章节。