需要解释当对象执行方法时对象如何被垃圾收集

Unm*_*kar 9 .net garbage-collection

在他的博客中,什么时候对象可用于垃圾收集?,Reymond Chen写道

在该对象上执行方法期间,对象可以符合收集条件.

此外,Curt Nichols通过这个例子展示了同样的观点

public class Program
    {
        static void Main(string[] args)
        {
            new TestClass().InstanceMethod();

            Console.WriteLine("End program.");
            Console.ReadLine();
        }
    }

    public sealed class TestClass
    {
        private FileStream stream;

        public TestClass()
        {
            Console.WriteLine("Ctor");

            stream = new FileStream(Path.GetTempFileName(), FileMode.Open);
        }

        ~TestClass()
        {
            Console.WriteLine("Finializer");

            stream.Dispose();
        }

        public void InstanceMethod()
        {
            Console.WriteLine("InstanceMethod");

            StaticMethod(stream);
        }

        private static void StaticMethod(FileStream fs)
        {
            GC.Collect();
            GC.WaitForPendingFinalizers();

            Console.WriteLine("StaticMethod"); 
            var len = fs.Length;
        }
    }
Run Code Online (Sandbox Code Playgroud)

输出如预期 -

Ctor
InstanceMethod
Finalizer
StaticMethod

ObjectDisposedException is thrown
Run Code Online (Sandbox Code Playgroud)

在这个例子中,我无法理解GC如何收集临时TestClass对象,因为它的成员stream被引用StaticMethod.

是的,雷蒙德说

GC不是追踪根,而是关于删除不再使用的对象

但是,在这个例子中TestClass对象仍在使用,不是吗?

请解释一下GC TestClass在这种情况下收集对象的权利如何?此外,更重要的是,开发人员应如何防范这些情况?

Ani*_*Ani 6

我无法理解GC是如何收集临时TestClass对象的,因为StaticMethod引用了它的成员流.

StaticMethod实际上并没有持有TestClass实例的stream成员的引用 - 它持有对引用(就GC而言)堆上的一些 FileStream对象.

请注意C#的默认传值语义.在这个声明中:

StaticMethod(stream);
Run Code Online (Sandbox Code Playgroud)

复制的值的stream字段被作为参数传递给静态方法通过.FileStream是引用类型,引用类型表达式的值是引用.因此,FileStream对堆上对象的引用将传递给方法,而不是(如您所想的那样)对TestClass对象的引用/内部引用

调用此FileStream对象时仍可访问的事实不会导致使对象(创建它并通过字段引用它)也可以访问."实时"对象通过引用它们使其他对象生动,而不是通过它们引用它们.GC.CollectTestClass

假设优化导致不需要的引用被"弹出",让我们看一下创建TestClass对象的可达性.

  • Main 调用后不需要引用它:
  • InstanceMethod,在this取消引用它以读取stream字段后,又不需要隐式传递的引用.此对象有资格进行收集.然后它调用:
  • StaticMethod反过来(如前所述)根本没有持有对象的引用.

因此,在读取TestClassstream字段之后不需要该对象,并且 StaticMethod执行时肯定有资格进行收集.