【问题标题】:passing data members by reference通过引用传递数据成员
【发布时间】:2013-05-02 12:40:02
【问题描述】:

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

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 如何确保引用参数在垃圾收集期间不会变为无效?它们是否像类引用一样调整?

【问题讨论】:

  • Eric Lippert 对@rightfold 的链接问题的回答完美地回答了这个问题。
  • 它们被调整了,因为任何方法参数都被认为是一个根,所有的根都被调整(它在“CLR via C#”一书中说)

标签: c# garbage-collection clr pass-by-reference


【解决方案1】:

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

抖动比这更进一步,它将引用标记为 GC_CALL_INTERIOR,指示可能是内部指针的参数的特定情况。您可以使用 SSCLI20 发行版中提供的源代码查看它是如何在 GC 内部处理的。不是很复杂,来自 gcsmp.cpp 的 sn-p,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 源代码以查看该代码。

【讨论】:

    【解决方案2】:

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

    您可以阅读有关 GC 工作原理的完整文章 here

    【讨论】:

    • 我说的是移动活着的对象,而不是处理死的对象。 (另外,i 并不“指向”一个对象,而是指向一个数据成员。)
    • 好吧,你说的只是 GC 的压缩阶段?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-08-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多