GC何时采取行动

时间:2013-11-07 09:38:42

标签: c# .net garbage-collection

我想知道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会释放一个元素的记忆是什么情况。

6 个答案:

答案 0 :(得分:4)

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

即使准备好收集对象,垃圾收集器也只能在以下时间运行:

  • 物理内存较低(操作系统会在有内存压力时告诉您的应用)
  • 分配对象使用的内存超过某个动态调整的阈值
  • 由于内存不足,无法进行新分配
  • 明确调用GC.Collect()
  • ..

答案 1 :(得分:1)

list1在test()完成后保留对列表的引用,并将在Test实例的生存期内保留该引用。因此,GC不会释放该列表,直到不再提及Test之后的某个时间。

&#34;&#34;&#34;&#34;发生可以被视为非确定性的。它会在它想要的时候做到。它几乎肯定不会马上做到。

答案 2 :(得分:1)

  

是否因为另一个元素捕获了地址,如果list2?

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

值得注意的是,指针变得无效,但它引用的内存仍然是“活着的”。因为还有另一个list1引用相同的内存

list1 = list2;

list1是一个全局变量,所以在这个具体案例中不受破坏。

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

答案 3 :(得分:1)

.NET GC是tracing, generational, mark-and-sweep collector

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

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

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

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

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

答案 4 :(得分:1)

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

首先,GC自动且异步地运行。它也很'聪明'。它仅在需要时运行,以最大限度地减少收集尝试次数。你永远不应该与它互动。

  

GC假设释放list2的内存,是因为   如果list2,另一个元素捕获了地址?运行test()后

list1成员list2本地变量list1始终为null - 无需收集任何内容。将{em>引用(没有指针在c#!中)指定给list2时,会将其创建为list1。现在只有在收集班级list2时才会创建Test

答案 5 :(得分:0)

我不确定我是否正确理解了您的问题,但GC会删除list2的内容,因为它只保留了很短的时间,因为它存在于堆栈而不是堆中。 / p>

所以,如果你想知道GC是否因为你已经分配了list1 = list2而清除它,那么没有。 List2也将保持活着状态,但由于方法结束而被杀死。 :)

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