带有对象引用的C#垃圾回收

本文关键字:对象引用 | 更新日期: 2023-09-27 18:01:07

在C#中,当我有两个对象obj1obj2由一个List<string>组成时,我将这两个对象都分配给同一个List<string>对象。

如果我对obj1的引用超出了范围,但对obj2的引用没有超出范围,那么obj1是否仍然有资格进行垃圾收集,或者是否因为仍然有对List<string>对象的引用而存在一些依赖性问题?

带有对象引用的C#垃圾回收

只要没有对obj1本身的引用,

obj1就应该有资格进行垃圾收集。

如果我对obj1的引用超出范围,但我对obj2的引用确实不是,obj1仍然有资格吗垃圾收集,或者有一些依赖性问题,因为仍然是对列表的引用对象

如果我理解正确,您的意思是obj1obj2都属于List<string>类型,并且都指向相同的List<string>实例。

obj1超出范围时,仍然会有obj2作为对List<string>实例的活动引用,因此不能对列表进行垃圾收集。

如果obj1是堆上引用类型(即其属性之一(的一部分,则它所占用的内存空间可能会作为外部对象的一部分进行垃圾收集。如果它只是堆栈上的引用,则不会涉及GC,因为当obj1超出范围时,堆栈将在方法调用结束时展开。

请记住,obj1只是对堆上某个对象的引用(在某种程度上是一个指针(——只有当不再有引用指向该对象时,该对象才可能被垃圾收集。

在您的情况下,obj1必须有资格进行垃圾收集。

您需要在此处查看Jon Skeet's answer。它清楚地解释了垃圾回收是如何在对象引用上工作的。

一个很好的Object's Lifetime in C#教程。

这个问题中定义了内存的三种用途:

  • 对被称为CCD_ 16的单个CCD_
  • 对被称为CCD_ 18的单个CCD_
  • List<string>

如果obj1超出范围,但obj2没有超出范围,则垃圾回收后只剩下以下内容:

  • 对被称为CCD_ 23的CCD_
  • List<string>

重要的是要记住,C#在大多数情况下都抽象掉了引用的概念,这样你就可以放心地将obj1obj2视为List<string>,而不是引用,而是引用它们。

obj1引用可能在本地调用堆栈中,而实例本身可能在堆中。因此,obj1(引用(仅在调用堆栈展开时才被清理。

如果obj1是List的成员,则在父List被垃圾收集之前,它不可用于垃圾收集。

因此:

List<string> l = new List<string>();
string a = "one";
l.Add(a);
{
    string b = "two";
    l.Add(b);
}

在该列表的末尾,a在作用域内,b在作用域外,但两者在列表l中仍有引用,因此两者都不符合垃圾收集的条件。