c# - "ref int m_a"如何让包含m a的对象不被GC回收?

标签 c# garbage-collection

class A
{
   public int m_a;
}

void fun(ref int a)
{
   ...
}

fun(ref new A().m_a);

在 fun 中,“ref int a”如何防止对象 (new A()) 在从 fun 返回之前被回收?

<example 0>
using System;

class A
{
    public int m_a;
    ~A()
    {
        Console.WriteLine("~A()");
    }
}

class Program
{
    static void fun(ref int a)
    {
        Console.WriteLine("Begin<<<<<<<<<<<<<<");
        a++;
        GC.Collect();
        GC.WaitForPendingFinalizers();

        Console.WriteLine("End>>>>>>>>>>>>>>>>>");
    }

    static void Main(string[] args)
    {
        fun(ref new A().m_a);

        Console.WriteLine("Over");
    }
}


output:
Begin<<<<<<<<<<<<<<
~A()
End>>>>>>>>>>>>>>>>>
Over

<example 1>
using System;

class A
{
    public int m_a;
    ~A()
    {
        Console.WriteLine("~A()");
    }
}

class Program
{
    static void fun(ref int a)
    {
        Console.WriteLine("Begin<<<<<<<<<<<<<<");
        a++;
        GC.Collect();
        GC.WaitForPendingFinalizers();

        //add a code
        a++;

        Console.WriteLine("End>>>>>>>>>>>>>>>>>");
    }

    static void Main(string[] args)
    {
        fun(ref new A().m_a);

        Console.WriteLine("Over");
    }
}

output:
Begin<<<<<<<<<<<<<<
End>>>>>>>>>>>>>>>>>
Over
~A()

请在 VS 中通过 Release模式构建。 我查看ASM代码,只加了两行:

             a++;
0000002f  mov         eax,dword ptr [ebp-4] 
00000032  inc         dword ptr [eax] 

两个例子之间的其他部分是相同的。 GC 如何确保变量 a 在机器码中不再有用?

最佳答案

这取决于 afun 中的使用方式。 GC 能够确定任何给定对象是否有根。在这种情况下,aA 实例中字段 m_a 的别名,并且该对象被认为是 Root过的。但是,如果 JIT 编译器确定 a 未在 fun 的其余部分中使用,则从该点开始在方法中,A 的实例将不再有根并且有资格进行垃圾收集。

一些例子:

void fun(ref int a)
{
   // forgot to use a. our object is already eligible for GC!
   for(int i = 0; i < 10; i++)
   {
      Console.WriteLine(i);
   }
}

void fun2(ref int a)
{       
   for(int i = 0; i < 10; i++)
   {
      Console.WriteLine(a);
   }
   // GC has to wait until a is no longer in use. now our object is eligible for GC.
}

void fun3(ref int a)
{
   // can't gc yet. a is still being used.
   int b = a;
   // b has a copy of the value in a so now our object is eligible for GC.
   for(int i = 0; i < 10; i++)
   {
      Console.WriteLine(b);
   }
}

更新:

我不是这在 clr 中如何实现的专家,但我的理解是使用 ref 会导致指向字段 m_a 的托管指针被传递到 fun。 GC 运行时,根据静态中对堆对象的引用、所有线程的调用堆栈和寄存器来确定根。我在这里猜测,但也许指向字段 m_a 的托管指针存储了对容器对象的引用。或者 GC 可以确定给定托管指针所在的对象。无论哪种方式,该对象都被标记为根自该托管引用。

关于c# - "ref int m_a"如何让包含m a的对象不被GC回收?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11306047/

相关文章:

c# - 非正式谬误导致堆栈溢出

c# - 重复类名上的 ASP.NET WebAPI 属性路由

java - 以编程方式了解java对象创建率

c# - 如果列表返回空显示信息

c# - Xamarin-在Gridview中创建一个额外的列,其垂直跨度为2

perl - Perl 中的垃圾收集

java - 使用 Spring 集成执行器 channel 时超出 GC 限制

c# - 垃圾邮件 GC.KeepAlive(KeyboardHookPointer) 有什么问题吗?

java - 什么是 "allocation pools for temporary objects"?

c# - 为什么c#不支持以接口(interface)为参数的对象?