Критерии инициирования сборки "мусора" в .NET

Я столкнулся с некоторым любопытным поведением относительно сборки "мусора" в .NET.

Следующая программа бросит OutOfMemoryException очень быстро (после того, как меньше, чем секунда на 32-разрядной, машине на 2 ГБ). Финализатор Нечто никогда не называют.

class Foo
{
    Guid guid = Guid.NewGuid();
    byte[] buffer = new byte[1000000];

    static Random rand = new Random();
    public Foo()
    {
        // Uncomment the following line and the program will run forever.
        // rand.NextBytes(buffer);
    }

    ~Foo()
    {
        // This finalizer is never called unless the rand.NextBytes
        // line in the constructor is uncommented.
    }

    static public void Main(string args[])
    {
        for (; ; )
        {
            new Foo();
        }
    }
}

Если rand.nextBytes строка будет не прокомментирована, то она будет работать до бесконечности, и финализатор Foo регулярно вызывается. Почему это?

Мое лучшее предположение - то, что в бывшем случае, или CLR или Windows VMM ленивы о выделении физической памяти. Буфер никогда не пишется в, таким образом, физическая память никогда не используется. Когда адресное пространство заканчивается, системные катастрофические отказы. В последнем случае система исчерпывает физическую память, прежде чем это исчерпает адресное пространство, GC инициирован, и объекты собраны.

Однако вот первая часть, не добираются. Принятие моей теории корректно, почему GC не инициировал, когда адресное пространство кончается? Если моя теория является неправильной, то, каково реальное объяснение?

6
задан Henk Holterman 19 April 2010 в 22:21
поделиться

1 ответ

На моей машине размер кода составляет 18 МБ, с этой строкой или без нее (XP SP3 x86, .Net 3.5 SP1, двухъядерный) .

Вероятно, на вашем компьютере происходит следующее: когда строка комментируется, программа тратит большую часть своего времени на выделение памяти и успевает выделить слишком много памяти до того, как поток сборщика мусора сможет освободить ее. Когда вы раскомментируете эту строку, программа тратит гораздо меньше времени на распределение и, следовательно, не может выделить слишком много до запуска потока GC.

Попробуйте заменить закомментированную строку на Thread.Sleep (0) ; если не вылетает, наверное, я прав.


Кстати, вы никогда не должны полагаться на финализатор - он не может быть вызван сразу после сборки объекта, или даже вообще. Вместо этого в реальном коде реализуйте интерфейс IDisposable и используйте финализатор, только если чрезвычайно важно, чтобы вызывалась Dispose () , даже если программист забыл это (например, освобождение общих сетевых / файловых ресурсов и т. д.)

1
ответ дан 17 December 2019 в 22:11
поделиться
Другие вопросы по тегам:

Похожие вопросы: