Как вызывается деструктор, когда сборщик мусора находится в действии [.NET]? - PullRequest
1 голос
/ 29 октября 2011

Я экспериментировал с сборщиком мусора и обнаружил странный счет iCnt на destructor звонке. Вот код: -

public class MyClass
{
    static long iCnt;
    public MyClass()
    {
        iCnt++;
    }

    ~MyClass()
    {
        iCnt--;
    }
    static public string ObjectCount
    {
        get
        {
            return iCnt.ToString();
        }
    }
}

Ниже приведен код для создания объектов, удаления объектов (разыменование путем присвоения null) и явного вызова GC.Collect(). У меня есть все это в форме победы, которая имеет Timer из interval = 100, таймер показывает текущий счет iCnt.

public partial class Form1 : Form
{
    MyClass[] Objs;
    public Form1()
    {
        InitializeComponent();
    }

    private void btnCreateObjects_Click(object sender, EventArgs e)
    {
        Objs = new MyClass[1000];
        for (int i = 0; i < 1000; i++)
        {
            Objs[i] = new MyClass();
        }
    }

    private void timer1_Tick(object sender, EventArgs e)
    {
        label2.Text = MyClass.ObjectCount;
    }
    private void btnDeleteObjects_Click(object sender, EventArgs e)
    {
        for (int i = 0; i < 1000; i++)
        {
            Objs[i] = null;
        }
    }

    private void btnInvokeGC_Click(object sender, EventArgs e)
    {
        GC.Collect();
    }
}

Теперь создайте объект, пока сборщик мусора не будет вызван автоматически (для меня это заняло 24 клика). Снова повторите это действие.

Я видел это iCnt <1000. Что меня смущает, как деструктор вызывал в этом сценарии. когда <code>iCnt <1000, нажмите на удалить объект, который ссылается на <code>Objs[1000]. Затем позвоните GC.Collect(), что делает счет iCnt <0 (очень странно). </p>

Может кто-нибудь объяснить мне это поведение. Заранее спасибо.

Ответы [ 2 ]

5 голосов
/ 29 октября 2011

Это довольно классическая ошибка потоков. Деструктор запускается в потоке финализатора асинхронно из потока, который увеличивает счетчик. Вы должны использовать Interlocked.Increment () и Decrement (), чтобы сделать это безопасно. Или используйте ключевое слово lock .

0 голосов
/ 30 октября 2011

Я думаю, что вам действительно нужно использовать выражение «использование». Как это:

с использованием (foo = new bar ()) {... code ...}

При использовании вы можете быть уверены, что событие dispose произойдет, когда код завершится, даже если он вызовет исключение. В ситуации, которую вы описали, сборщик мусора в C # решает, когда вызывать событие dispose (которое вызывает ваш деструктор). Таким образом, у вас могут быть длительные периоды, когда объекты сидят без ссылок на них, но не располагаются одинаково.

...