GC 何时采取行动



我想知道 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 的相同地址吗?运行测试() 后

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

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

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

  • 物理内存不足(操作系统会在内存压力时告知你的应用)
  • 分配对象使用的内存超过动态调整的特定阈值
  • 无法进行新的分配,因为没有足够的可用内存
  • 气相色谱。显式调用了 Collect()
  • ..

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

何时"之后"发生可以被视为不确定的。它会在它想要的时候做。它几乎肯定不会立即做到这一点。

是因为另一个元素捕获了 list2 的地址吗?

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

值得强调的是,指针变得无效,但它所指的内存仍然"活着"。因为还有另一个list1指的是同一个内存

list1 = list2;

list1是全局 VAR,因此在此具体情况下不会受到破坏。

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

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

首先,GC 自动异步运行。它也是"聪明的"。它只会在需要时运行,以最大程度地减少收集尝试的次数。您永远不必与之交互。

GC 应该释放 list2 的内存,这是因为 另一个元素捕获了地址 如果 list2?运行测试() 后

list1是班级成员list2是一个局部变量list1总是null - 没有什么可收集的。将 list2 分配给 list1 时,将创建对 的引用(在 c# 中没有指针)。 现在,只有在收集类Test时才会创建list2

.

NET GC 是一个跟踪、生成、标记和扫描收集器。

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

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

  2. 由其他可访问对象引用。

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

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

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

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

这里有一篇关于GC的小型博客文章:http://it-ca.net/blogdylan/?p=354

最新更新