我想知道 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 是一个跟踪、生成、标记和扫描收集器。
它永远不会收集可访问的对象,其中可访问的对象是:
从调用堆栈中的任何位置(即当前正在调用的函数中的所有局部变量和参数)以及任何全局变量引用。这些对象称为根。
由其他可访问对象引用。
在您的情况下,new List<int>()
语句在内存中创建一个新的列表实例,该实例最初由 list2
引用。如果您没有将其分配给 list1
,则一旦list2
超出范围(然后在将来的某个时间收集),它就有资格收集。
由于您使list1
字段引用了同一实例,因此在离开test1
方法后,您仍然会留下对该(唯一的)对象实例的强引用。
我不确定我是否正确理解了您的问题,但是 GC 将删除 list2 的内容,因为它只保持活动时间很短,因为它存在于堆栈而不是堆上。
因此,如果您想知道 GC 是否因为您分配了 list1=list2 而清除了它,那么没有。List2 也会保持活动状态,但由于方法结束,它会被杀死。:)
这里有一篇关于GC的小型博客文章:http://it-ca.net/blogdylan/?p=354