5

如果我通过引用函数传递数据成员,并且在该函数运行时,垃圾收集器开始运行并将包含该数据成员的对象移动到内存中,会发生什么情况?

class SomeClass
{
    int someDataMember;

    void someMethod()
    {
        SomeClass.someFunction(ref someDataMember);
    }

    static void someFunction(ref int i)
    {
        i = 42;

        int[] dummy = new int[1234567890];
        // suppose the Garbage Collector kicks in here

        i = 97;
    }
}

CLR 如何确保引用参数在垃圾收集期间不会变得无效?它们是否像类引用一样进行了调整?

4

2 回答 2

5

好吧,垃圾收集器的生活并不容易。但它知道如何处理这样的内部指针。在 C# 和 VB.NET 等托管语言中隐藏得很好,它在 C++ 中可见,其中内部指针可以通过语言语法轻松生成。C++ Primer 的 Stan Lippman 有一篇关于它们的博客文章interior_ptr,给出了C++/CLI 中可用关键字的一些主要动机。

抖动比这更进一步,它将引用标记为 GC_CALL_INTERIOR,指示可能是内部指针的参数的特定情况。您可以使用 SSCLI20 发行版中提供的源代码查看它是如何在 GC 内部处理的。它不是很复杂,来自 gcsmp.cpp 的一个片段,GCHeap::Relocate() 方法:

   if (flags & GC_CALL_INTERIOR)
   {
       if ((o < gc_heap::gc_low) || (o >= gc_heap::gc_high))
       {
           return;
       }
       o = gc_heap::find_object (o, gc_heap::gc_low);

       offset = (BYTE*)object - o;
   }

因此,简而言之,通过检查 GC 堆段下限/上限的指针,一个非常快速的测试发现它不能是引用引用类型对象成员的指针。然后进行一些挖掘以将内部指针映射到包含该成员的对象。查看 SSCLI20 源代码以查看该代码。

于 2013-05-08T11:00:27.143 回答
0

垃圾收集器保留一个指向对象的所有指针的列表。如果没有更多指向该对象的指针,它只会释放对象。
在您的情况下,您的函数将有一个指向该对象的指针(名为“i”),因此 GC 永远不会处理该对象。

您可以在此处阅读有关 GC 工作原理的完整文章。

于 2013-05-08T10:17:37.663 回答