简体   繁体   English

GC何时采取行动

[英]When does the GC take action

I wonder what are the situations of the GC to free the memory of a pointer. 我想知道GC在什么情况下释放指针的内存。

For example: 例如:

public class Test
{
    public List<int> list1;

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

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

        list1 = list2;
    }
}

The GC was suppose to free the memory of list2, does it because another element share the same address of list2? GC假定释放了list2的内存,是否因为另一个元素共享了list2的相同地址? After the run of test() 运行test()之后

What are the situations which the G will free the memory of an element. G将在什么情况下释放元素的内存?

In your example you create list2 as a local variable, but then you retain the reference to the underlying object in list1 before the method exits, which means the object you created in test() won't be collected (until list1 gets out of scope or changes the reference). 在您的示例中,您将list2创建为局部变量,但是在方法退出之前,您将对底层对象的引用保留在list1中,这意味着将不会收集您在test()中创建的对象(直到list1超出范围)或更改参考)。 Your object is ready to be collected only when there are no strong references to it (read about weak references if you want to know more on this subject). 仅当没有引用时,才可以收集您的对象(如果您想进一步了解该主题,请阅读弱引用)。

Even when the object is ready to be collected, garbage collector will only run when: 即使准备好收集对象,垃圾收集器也只会在以下情况下运行:

  • There is low physical memory (OS will tell your app when there is memory pressure) 物理内存不足(操作系统会在内存不足时通知您的应用)
  • Memory used by allocated objects surpasses a certain threshold which is adjusted dynamically 分配对象使用的内存超过特定阈值,该阈值可以动态调整
  • New allocation cannot be made because not enough memory available 无法进行新分配,因为没有足够的可用内存
  • GC.Collect() was called explicitly GC.Collect()被显式调用
  • .. ..

list1 retains a reference to the list after test() completes and will retain that reference for the lifetime of the instance of Test . 在test()完成之后, list1保留对列表的引用,并将在Test实例的生存期内保留该引用。 The GC will not free up that list therefore until sometime after there is no longer any reference to Test . GC将不会释放该列表,因此要等到不再有任何对Test引用之后的某个时间。

When that "sometime after" occurs can be viewed as non-deterministic. 当“之后某时”发生时,可以视为不确定的。 It'll do it as and when it wants to. 它会在需要的时候做。 It almost certainly won't do it straight away. 几乎可以肯定不会马上做到。

does it because another element caught the address if list2? 是因为list2另一个元素捕获了地址?

No, it because list2 is no longer available out of scope of test(..) method. 不,这是因为list2test(..)方法范围之外不再可用。

Worth mantioning, that the pointer becomes invalid, but the memory it refers to is still "alive". 值得一提的是,该指针变为无效,但它所指向的内存仍然是“活动的”。 Because there is another list1 that refers to the same memory 因为还有另一个list1引用相同的内存

list1 = list2;

and list1 is a global var, so is not subject for destruction in this concrete case . 并且list1是全局变量,因此在这种具体情况下不被破坏。

And more: it's not a must that GC actually frees a memory. 还有更多: GC实际上不必释放内存。 Correct to say that the memory is marked to be garbage collected, but will be it actually cleaned or not is subject of other validations. 正确地说,该内存被标记为已被垃圾回收,但是它是否会被实际清除还需要其他验证。

.NET GC is a tracing, generational, mark-and-sweep collector . .NET GC是一个跟踪的,世代相继的标记和清除收集器

It will never collect objects which are reachable , where reachable objects are ones: 它永远不会收集到达的对象,其中可到达的对象是:

  1. which are referenced from anywhere in the call stack (that is, all local variables and parameters in the functions currently being invoked), and any global variables. 可以从调用堆栈中的任何位置(即当前正在调用的函数中的所有局部变量和参数)以及任何全局变量进行引用。 These objects are called roots . 这些对象称为roots

  2. which are referenced by other reachable objects. 其他可到达对象引用的对象。

In your case, the new List<int>() statement creates a new list instance in memory, which is initially referenced by list2 . 在您的情况下, new List<int>()语句在内存中创建一个新的列表实例,该实例最初由list2引用。 If you didn't assign it to list1 , it would have been eligible for collection as soon as list2 went out of scope (and then collected some time in the future). 如果您未将其分配给list1 ,则只要list2超出范围(然后在以后的某个时间收集),它就可以进行收集。

Since you made your list1 field reference that same instance, after leaving the test1 method you are still left with a strong reference to that (one and only) object instance. 由于您使list1字段引用了相同的实例,因此在离开test1方法之后,您仍然会强烈引用该对象实例(唯一的实例)。

Your terminology is a bit mixed so I'll try to correct that. 您的用语有点mixed贬不一,所以我将尝试纠正它。

Firstly, the GC runs automatically and asynchronously. 首先,GC自动并异步运行。 It is also 'smart'. 它也是“智能”的。 It will only run when required, to minimize the number of collection attempts. 它仅在需要时运行,以最大程度地减少收集尝试的次数。 You should never have to interact with it. 您永远不必与之交互。

The GC was suppose to free the memory of list2, does it because another element caught the address if list2? GC假定释放了list2的内存,是否因为list2另一个元素捕获了地址? After the run of test() 运行test()之后

list1 is a class member . list1是类成员 list2 is a local variable . list2是一个局部变量 list1 is always null - there is nothing to collect. list1始终是null -没有什么可以收集。 A reference ( no pointers in c#!) to list2 is created when you assign it to list1 . 引用分配给list1时,将创建对list2引用 (在c#中没有指针!)。 list2 will now only be created when the class Test is collected. 现在仅在收集Test类时才创建list2

I'm not sure if I understand your question correctly, but the GC will remove the content of list2 because it is kept alive for only a short amount of time, due to it living on the stack and not the heap. 我不确定我是否正确理解了您的问题,但是GC将删除list2的内容,因为list2驻留在堆栈上,而不是堆上,因此仅保留了很短的时间。

So, if you're wondering if the GC clears it because you've assigned list1=list2, then no. 因此,如果您想知道GC是否由于分配了list1 = list2而将其清除,则不会。 List2 would be kept alive as well but it gets killed off due to the method ending. List2也将保持活动状态,但是由于方法结束而被杀死。 :) :)

Here is a small blogpost that goes a bit more in-depth on the GC: http://it-ca.net/blogdylan/?p=354 这是一个关于GC的小博客文章: http ://it-ca.net/blogdylan/?p=354

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM