Собирать объекты все еще в области - GC.Collect - PullRequest
4 голосов
/ 21 июня 2011

Я прочитал эту статью: http://blogs.msdn.com/b/oldnewthing/archive/2010/08/10/10048149.aspx и, честно говоря, я не понимаю всех деталей.Насколько я понимаю, в приведенном ниже коде c следует собирать, даже если я не установил для c значение null.Другое дело, что распределение, происходящее во время foreach, кажется, не освобождается, пока мы находимся в рамках одной и той же функции.(См. Пример ниже)

class Program
{
    public class SomeClass
    {
        public byte[] X;

        public SomeClass()
        {
            X = new byte[1024 * 1024 * 100];
            X[155] = 10;
        }
    }

    static void Main()
    {
        Console.WriteLine("Memory: " + GC.GetTotalMemory(false));

        SomeClass c;
        c = new SomeClass();

        Console.WriteLine("Memory: " + GC.GetTotalMemory(false));
        GC.Collect();
        Console.WriteLine("Memory: " + GC.GetTotalMemory(true));
        Console.ReadKey();

        /*
         * Output:
         * 
         * Memory: 186836
         * Memory: 105044468
         * Memory: 104963676
         * 
         */
    }
}

EDIT Решение для первого примера: режим отладки (не работает в отладчике, но даже в режиме компиляции).Если я использую Release, он будет работать как положено: c собирается даже без установки на ноль.Для второго примера применяется то же самое.

Второй пример

static void Main(string[] args)
{
    Console.WriteLine("Startup Memory: " + GC.GetTotalMemory(false));

    var obj = BOObject.Get();

    Console.WriteLine("Fetched Object: " + GC.GetTotalMemory(false));
    GC.Collect();
    Console.WriteLine("Fetched Object (Collected): " + GC.GetTotalMemory(false));

    foreach (var node in obj.Traverse())
    {
        string name = node.Name;
    }

    Console.WriteLine("Traversed: " + GC.GetTotalMemory(false));
    GC.Collect();
    Console.WriteLine("Traversed (collected): " + GC.GetTotalMemory(false));

    obj = null;

    GC.Collect();
    Console.WriteLine("collected: " + GC.GetTotalMemory(true));
    Console.Read();
}

Вывод:

Память при запуске: 193060 Извлечено: 8972464 Извлечено (собрано): 5594308 Пройдено: 272553096 Просмотрено (собрано): 269564660 собрано: 269564048

Если я помещаю цикл foreach в другую функцию и вызываю эту функцию, то используемая память после вызова .Collect составляет около 5800000. Так почему мусор не собирается, когда у меня есть foreachцикл в той же функции?

Ответы [ 2 ]

6 голосов
/ 21 июня 2011

Упоминается в комментариях к статье Рэймонда и в статье MSDN Юна Джина здесь , что

Фактически, для отлаживаемого кода JIT продлевает время жизни для каждой переменной до концаfunction.

Поэтому ваша коллекция не будет собрана в режиме отладки, как вы обнаружили, и почему она будет собрана в режиме выпуска.

0 голосов
/ 21 июня 2011

Поведение сборщика мусора не является детерминированным и не следует ожидать, что оно будет детерминированным.Не полагайтесь на GC.

Вы спрашиваете, почему GC не собирает ваш мусор в данный момент времени.Лучшим вопросом было бы, почему является коллекцией в данный момент времени.

...