我想知道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会释放一个元素的记忆是什么情况。
答案 0 :(得分:4)
在您的示例中,您将list2创建为局部变量,但在方法退出之前保留对list1中基础对象的引用,这意味着您将不会收集在test()中创建的对象(直到list1获取超出范围或更改参考)。只有在没有强引用的情况下才能收集您的对象(如果您想了解有关此主题的更多信息,请阅读弱引用)。
即使准备好收集对象,垃圾收集器也只能在以下时间运行:
答案 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。
永远不会收集可到达的对象,其中可到达的对象是:
从调用堆栈中的任何位置引用(即,当前正在调用的函数中的所有局部变量和参数)以及任何全局变量。这些对象称为 roots 。
由其他可到达对象引用。
在您的情况下,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