C# 中的对象引用垃圾回收

3
在C#中,当我有两个对象obj1、obj2,它们都由一个List组成,并且我将这两个对象都赋值给同一个List对象时。如果我的对obj1的引用超出了范围,但对obj2的引用没有超出范围,那么obj1是否仍然符合垃圾回收的条件,或者是否存在某些依赖关系,因为仍然存在对List对象的引用?

8
好问题,但您能否以代码形式书写出来? - harpo
1
看起来是个好问题,但我不太确定,因为obj1obj2和List<string>对象的情况不太清楚...你能澄清一下吗? - Matt
这里被接受的答案似乎完全错误。即使这是永远以前的事情。在我看来,OP描述了类似于这样的东西:var list = new List<string>(); object obj2 = list; { object obj1 = list; }。垃圾回收不影响变量。它影响对象。obj1obj2不会被垃圾回收。它们存在于堆栈上,并在函数或方法返回时清除。首先分配给list的实例是唯一真正的对象,只有在所有对它的引用都被销毁(通过超出范围或垃圾回收)之后,才能进行垃圾回收。 - bambams
5个回答

1

只要没有对obj1本身的引用,obj1就应该有资格进行垃圾回收。


1
如果你指的是由obj1定义的指针,而不是被obj1指向的List<string>实例,则这是正确的。 - Enigmativity

1
如果我的对 obj1 的引用超出了作用域,但是对 obj2 的引用没有超出作用域,那么 obj1 是否仍然适合进行垃圾回收,或者由于仍然存在对 List 对象的引用而存在某些依赖性问题?
如果我理解正确,您的意思是 obj1 和 obj2 都是类型为 List 的对象,并且都指向同一个 List 实例。
当 obj1 超出作用域时,仍然会有 obj2 作为 List 实例的活动引用,因此该列表无法进行垃圾回收。
如果 obj1 是堆上的引用类型(即其属性之一),则其占用的内存空间可能作为外部对象的一部分进行垃圾回收。如果它只是栈上的引用,则不涉及 GC,因为在方法调用结束时,当 obj1 超出作用域时,栈将被展开。
请记住,obj1只是指向堆上对象的引用(一种指针)- 只有当没有引用指向它时,该对象才可以被垃圾回收。

0
在你的情况下,obj1必须符合条件才能进行垃圾回收。
你需要查看 Jon Skeet的 答案。它清楚地解释了对象引用上的垃圾回收如何工作。
关于C#中对象生命周期,这是一篇很好的教程供你学习。

Jon Skeet在他的回答中说:“只有当一个对象不再被任何东西引用时,它才会被垃圾收集。” 在这种情况下,obj1obj2引用同一个对象。因此它不符合收集条件。 - Enigmativity

0

这个问题中定义了三种内存使用方式:

  • obj1是单个List<string>实例的引用。
  • obj2是单个List<string>实例的引用。
  • 单个List<string>实例本身。

如果obj1超出作用域,但obj2没有,那么垃圾回收后仅剩下以下内容:

  • obj2所引用的List<string>实例。
  • 单个List<string>实例本身。

重要的是要记住,在大多数情况下,C#抽象了引用的概念,因此您可以安全地将obj1obj2视为List<string>而不是引用,但它们确实是引用。

很可能obj1引用在本地调用堆栈中,而不是实例本身,实例本身很可能在堆上。因此,当调用堆栈被展开时,obj1(引用)才会被清除。


-1
如果obj1是列表的成员,则在父列表被垃圾回收之前,它将不会被垃圾回收。因此:
List<string> l = new List<string>();

string a = "one";
l.Add(a);

{
    string b = "two";
    l.Add(b);
}

在此列表结束时,a 在作用域内,b 不在作用域内,但两者仍然在列表l中具有引用,因此两者都不符合垃圾回收的条件。

不确定为什么这个被踩了 - 一个解释为什么它是错误的或者是一个糟糕的答案会很好。 - JT.
可能是因为它回答了错误的问题。 - bambams

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接