0

我想知道GC释放指针内存的情况是什么。

例如:

public class Test
{
    public List<int> list1;

    public void test()
    {
        List<int> list2 = new list<int>();

        list2.Add(1);
        list2.Add(1);

        list1 = list2;
    }
}

GC 应该释放 list2 的内存,是因为另一个元素共享 list2 的相同地址吗?运行 test() 之后

在什么情况下 G 会释放元素的内存。

4

6 回答 6

4

在您的示例中,您将 list2 创建为局部变量,但随后在方法退出之前保留对 list1 中基础对象的引用,这意味着您在 test() 中创建的对象将不会被收集(直到 list1 超出范围或更改参考)。只有当没有引用时,您的对象才准备好被收集(如果您想了解有关此主题的更多信息,请阅读弱引用)。

即使对象已准备好被收集,垃圾收集器也只会在以下情况下运行:

  • 物理内存不足(当有内存压力时,操作系统会告诉您的应用程序)
  • 分配对象使用的内存超过某个阈值,该阈值是动态调整的
  • 无法进行新分配,因为没有足够的可用内存
  • GC.Collect() 被显式调用
  • ..
于 2013-11-07T10:00:28.577 回答
1

list1在 test() 完成后保留对列表的引用,并将在 的实例的生命周期内保留该引用Test。因此,GC 不会释放该列表,直到不再引用Test.

当“之后的某个时间”发生时,可以被视为非确定性的。它会随心所欲地做。它几乎肯定不会立即执行此操作。

于 2013-11-07T09:42:49.083 回答
1

是不是因为另一个元素在list2中捕获了地址?

不,这是因为list2不再可用,超出了test(..)方法的范围。

值得一提的是,指针变得无效,但它所指的内存仍然“活着”。因为有另一个list1指代相同的记忆

list1 = list2;

并且list1是一个全局变量,因此在这个具体案例中不会被破坏。

还有更多:GC实际上释放内存并不是必须的。正确地说内存被标记为垃圾收集,但它是否真正被 清理是其他验证的主题。

于 2013-11-07T09:43:13.520 回答
1

.NET GC 是一个跟踪、分代、标记和清除收集器

它永远不会收集可到达的对象,其中可到达的对象是:

  1. 从调用堆栈中的任何位置(即当前正在调用的函数中的所有局部变量和参数)以及任何全局变量引用它们。这些对象称为

  2. 由其他可达对象引用。

在您的情况下,该new List<int>()语句在内存中创建一个新的列表实例,该实例最初由list2. 如果您没有将其分配给list1,那么一旦list2超出范围(然后在将来的某个时间收集),它就有资格被收集。

由于您使list1字段引用了同一个实例,因此在离开该test1方法后,您仍然会留下对该(唯一的)对象实例的强引用。

于 2013-11-07T09:43:47.137 回答
1

你的术语有点混杂,所以我会试着纠正它。

首先,GC 自动异步运行。它也很“聪明”。它只会在需要时运行,以尽量减少收集尝试的次数。您永远不必与它交互。

GC应该释放list2的内存,是不是因为另一个元素捕获了list2的地址?运行 test() 之后

list1是班级成员list2是一个局部变量list1总是null- 没有什么可收集的。当您将分配. 现在只会在收集类时创建。list2list1list2Test

于 2013-11-07T09:45:07.963 回答
0

我不确定我是否正确理解了您的问题,但是 GC 将删除 list2 的内容,因为它仅在很短的时间内保持活动状态,因为它位于堆栈而不是堆中。

因此,如果您想知道 GC 是否因为您分配了 list1=list2 而将其清除,那么不会。List2 也将保持活动状态,但由于方法结束而被杀死。:)

这是一篇关于 GC 更深入的小博文:http://it-ca.net/blogdylan/?p= 354

于 2013-11-07T09:43:42.117 回答