GC运行后对象会发生什么?

now*_*ed. 1 .net c# garbage-collection

请考虑以下陈述

void foo()
{
    string text = "something";
    int a = 10;
    int b = a;

    var array = new int[5]{2,1,3,5,4};

    GC.Collect();
}



**Stack**           **Heap**

text = 0x20         0x20 something

a = 10

b = 10

array = 0x50:0x55   0x50 2
                    0x52 1
                    0x53 3
                    0x54 5
                    0x55 4
Run Code Online (Sandbox Code Playgroud)

一些假设:

  1. 在方法结束时调用GC.Collect().
  2. GC运行(假设).

问题是:

  1. 堆中有什么价值?

    我回答了内存位置0x20,0x50-0x55将被回收并删除.他再次问道,记忆位置有什么价值?我猜可能是垃圾值.他说错了.(WTX?)

  2. 堆栈中的项目会发生什么?text,a,b,array包含哪些值?

    我回答说,因为它们包含的引用已被删除,它们也将被回收.他问现在变量的值是多少.

  3. 在GC Collection之后重绘上面的表格列.

    GC运行后

    **Stack**           **Heap**
    
    text (cleared)      0x20 Garbage/NULL
    
    a (cleared) 
    
    b (cleared) 
    
    array (cleared)     0x50 Garbage/NULL
                        0x52 Garbage/NULL
                        0x53 Garbage/NULL
                        0x54 Garbage/NULL
                        0x55 Garbage/NULL
    
    Run Code Online (Sandbox Code Playgroud)

结果:他说答案不正确.我想念的是什么想法吗?

ang*_*son 5

不可能给出一个确定性的答案,但有些人会想到这种行为.

首先,所有变量都是局部变量.因此,方法返回后,这些变量超出范围.内存(或CPU寄存器)中的确切位置现在包含未知内容.其他事情现在可能生活在那个记忆区域,我们不知道.我们无法知道.因此,他们被清除了吗?谁知道.

但是,对于所有意图和目的,返回方法,这些变量不再存在.

如果您认为"这些变量存在于堆栈中",请注意堆栈是一个实现细节.

此外,您还分配了两个堆对象,一个字符串和一个数组.

由于这些只是在方法返回后超出范围的局部变量引用,因此这些变量不再被认为是有效的并且有资格进行收集.

但是,这里的"收集"是什么意思?这是否意味着垃圾收集器清除了内存区域?一点也不.

相反,当垃圾收集内存时,它实际上是相反的,它收集生物.这些对象在内存中被压缩并移动,并且该字符串和该数组所在的区域可被其他对象覆盖.可能是仅包含零的数组,在这种情况下,内存区域可能看起来"已清除",但可能不是.

但是,坚持下去,那个字符串,它会发生一些特别的事情.由于串写在源代码作为文字它实际上是实习的程序启动时.因此,它不会被收集,它仍将存在于内存中.换句话说,该字符串仍处于活动状态,位于内存中的某处.当变量引用它时,它可能与其他地方相同.我们无法知道.

但是,构成数组对象的字节在压缩活动对象时可被垃圾收集器覆盖.

好的,所以这一切都返回方法发生.

如果在方法返回之前GC.Collect()运行垃圾收集周期会发生什么?

好吧,如果你是一个RELEASE版本,上面的一切仍然存在.如果在方法中不再使用该变量,那么在引用堆上的某个东西的方法中有一个局部变量的事实就没有任何意义(即,您已经在执行时间轴中传递了最后一个用法).

但是,如果您处于DEBUG构建中,或者附加了调试器,则所有局部变量范围都会延长到方法的末尾.因此,它们仍被视为实时引用,并且还将堆上的对象保持活动状态.在这种情况下,将不会收集数组.

但是,无论何时运行垃圾收集,堆对象在内存中的位置地址都可能会发生变化,因为对象与其他对象一起压缩或升级到不同的一代.


以下是您问题的实际答案:

以上大部分是实施细节.我们不应该关心的事情,因为它可能会因优化而改变.

我们可以解释很多事情,但是我们不应该如何处理实际的底层内存.

你在评论中说过,你以为你是在编剧作家面试中,我会说这种感觉是正确的.如果您要访问Microsoft的JIT或内存管理团队,那么至少可以将这些内容的一些知识作为工作的一部分进行教学,但如果您已经知道,可能会获得奖励.

但是,对于普通的.NET程序员来说,这是不必要的.其他聪明的人关心这一点.