简体   繁体   English

c#中的垃圾收集误区

[英]Garbage Collection misunderstanding in c#

i have searched on google not getting what i want. 我搜索谷歌没有得到我想要的东西。 i don't know i am right or wrong. 我不知道我是对还是错。 look , i have trying to understand GC.Collect() so here is the code.. 看,我试图了解GC.Collect()所以这里是代码..

public class SomePublisher
{
    public event EventHandler SomeEvent;
}

public class SomeSubscriber
{
    public static int Count;

    public SomeSubscriber(SomePublisher publisher)
    {
        publisher.SomeEvent += new EventHandler(publisher_SomeEvent);
    }

    ~SomeSubscriber()
    {
        SomeSubscriber.Count++;
    }

    private void publisher_SomeEvent(object sender, EventArgs e)
    {
        // TODO: something
    }
}

i do this in my main thread.. 我在我的主线程中这样做..

 SomePublisher publisher = new SomePublisher();

        for (int i = 0; i < 10; i++)
        {
            SomeSubscriber subscriber = new SomeSubscriber(publisher);
            subscriber = null;
        }

        GC.Collect();
        GC.WaitForPendingFinalizers();

        Console.WriteLine(SomeSubscriber.Count.ToString());
        Console.ReadLine();

i am getting output 0 but it should bebe 10 according to me because GC.Collect() must have remove class1 objects from memory so class1 destructor must be called so the count must be increased to 10..can any body explain this.. 我得到输出0,但根据我应该是10,因为GC.Collect()必须从内存中删除class1对象,所以必须调用class1析构函数,所以计数必须增加到10 ..可以任何正文解释这个..

(Note also that C# does not have destructors 1 , it has finalizers. These are very different things, and you should not confuse them.) (另请注意,C#没有析构函数1 ,它有终结器。这些是非常不同的东西,你不应该混淆它们。)

The "problem" is on this line: “问题”就在这条线上:

publisher.SomeEvent += new EventHandler(publisher_SomeEvent);

This creates a delegate targeting the publisher_SomeEvent() method of the particular object instance, and adds this delegate to the invocation list for the publisher.SomeEvent event. 这将创建一个以特定对象实例的publisher_SomeEvent()方法为目标的委托,并将此委托添加到publisher.SomeEvent事件的调用列表中。 This delegate object references the target object, and it is preventing the object from being collected! 此委托对象引用目标对象,并阻止对象的收集! (This is a good thing -- if you take a delegate to a method on a particular object then you don't want that object being collected until the delegate is no longer referenced.) (这是一件好事 - 如果您将委托委托给特定对象上的方法,那么在不再引用委托之前,您不希望收集该对象。)

This technically isn't a problem at all, but rather is the runtime keeping objects alive that are still referenced. 这在技术上根本不是问题,而是运行时保持对象仍然存在仍然被引用。

To illustrate, this is the chain of references: 为了说明,这是参考链:

SomePublisher -+-> EventHandler --> SomeSubscriber
               |
               +-> EventHandler --> SomeSubscriber
               |
               +-> (Eight more...)

You need to do one of two things before calling GC.Collect() : 在调用GC.Collect()之前,您需要执行以下两项操作之一:

  1. Unsubscribe from the event before releasing each SomePublisher object. 在释放每个SomePublisher对象之前取消订阅该事件。 This will make both the EventHandler delegate instances and the SomeSubscriber instances they reference eligible for collection. 这将使EventHandler委托实例和它们引用的SomeSubscriber实例都有资格进行收集。
  2. Set publisher = null; 设置publisher = null; . This will cause the entire object graph to become eligible for collection. 这将导致整个对象图符合收集条件。

In both cases, this will release all references to the SomeSubscriber objects. 在这两种情况下,这将释放对SomeSubscriber对象的所有引用。


1 Note that the C# specification does call these blocks of code "destructors," but this is a horrible name. 1请注意,C#规范确实将这些代码块称为“析构函数”,但这是一个可怕的名称。 Those familiar with garbage-collected languages will be confused by it, as "finalizer" is the widespread term for code that is invoked by the garbage collector when an object is no longer reachable. 那些熟悉垃圾收集语言的人会对它感到困惑,因为“终结器”是垃圾收集器在不再可以访问对象时调用的代码的广泛术语。 C++ developers in particular will expect the destructor to be executed at a different time. 特别是C ++开发人员会期望析构函数在不同的时间执行。 So yes, C# has something called a "destructor," but it is not a destructor. 所以是的,C#有一个叫做“析构函数”的东西,但它不是一个析构函数。 (Saying something doesn't make it so!) (说些什么不是这样!)

The finalizers of SomeSubcriber objects will not be called till end. SomeSubcriber对象的终结器直到最后才会被调用。 Because even though SomeSubscriber objects are set to null, its memory is still being referenced by the event SomeEvent of SomePublisher object, which is alive till the end of application. 因为即使SomeSubscriber对象设置为null,它的内存仍然被SomePublisher对象的事件SomeEvent引用,该对象在应用程序结束之前一直存在。 Thus when GC.Collect() is called, garbage collector won't find any objects to put in finalizer queue. 因此,当调用GC.Collect()时,垃圾收集器将找不到要放入终结器队列的任何对象。

public SomeSubscriber(SomePublisher publisher)
{
// publisher.SomeEvent += new EventHandler(publisher_SomeEvent);
}

If we can replace the constructor of SomeSubcriber by the code above, then we will get the result as 10 in console. 如果我们可以通过上面的代码替换SomeSubcriber的构造函数,那么我们将在控制台中将结果作为10。

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

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