Случаи, когда он полезен для сбора и точного уплотнения для других процессов - PullRequest
0 голосов
/ 18 мая 2018

Извините за то, что столкнулся с вопросом «зачем собирать?»снова.В процессе C # обычно не рекомендуется собирать память вручную, чтобы освободить ОЗУ.Я в целом согласен.

Чтобы сделать это, вам необходимо:

Вызывается несколько причин того, почему это бесполезно (и, возможно, противодействует).Я в целом согласен, но я не могу не задаться вопросом, опасно ли это.

Если мы этого не сделаем, случается, что (по крайней мере, с сервером GC и .NET 4.5) система может выделить несколькоГБ физической памяти для вашего процесса, которые на самом деле не используются живыми объектами.Особенно LOH может никогда не быть сжатым и использовать много оперативной памяти, которая фактически свободна с точки зрения менеджера памяти C #.Я испытываю это каждый день с процессами, имеющими 20 ГБ физической памяти, выделенной системой, используемой во время пиковых вычислений с интенсивным использованием ОЗУ несколько часов назад, но только небольшая часть все еще используется.

Насколько я вижу, на машинах до сих пор нет явных проблем с производительностью.Обычно утверждают, что это никогда не является проблемой, и я (почти) согласен с этим.Основным аргументом в аргументации является то, что процесс не получает доступ к «свободной» оперативной памяти в LOH и, следовательно, перемещается на диск системой (Windows), по крайней мере, если объем оперативной памяти заканчивается.Этот ответ очень хорошо объясняет это: Когда память, выделенная процессом .NET, освобождается обратно в Windows

С точки зрения других процессов ... еще есть "беспокойство ".

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

Но есть еще один момент, который вызывает больше беспокойства.Может ли система действительно переместить неиспользованную оперативную память на диск?Что, если LOH фрагментирован с 99% свободного пространства, чередующегося с 1% используемого пространства.Я предполагаю, что система работает с большими сегментами, так что практически ни один сегмент не будет «использован на 0%».Может быть, это сложнее или может быть, это неверно.Что вы знаете об этом?

Мне интересны люди, имеющие некоторый опыт в этом.Наблюдал ли ты случаи, когда теория «тебе не нужно собирать деньги» идет не так, и по каким-то причинам оказалось, что делать это не в порядке? (и вы знаете почему) .

Ответы [ 2 ]

0 голосов
/ 22 ноября 2018

Я работал над этим вопросом некоторое время.Вывод таков:

  • Фрагментация LOH имеет незначительное значение с точки зрения потребления ОЗУ
  • однако это "немного" важно в некоторых сценариях

В этой статье говорится, что может быть полезно сжать кучу больших объектов: Сжатие кучи больших объектов: стоит ли ее использовать? .Он говорит много правды и практически полезен, но немного поверхностен.Полезность сжатия LOH должна быть изучена вместе с подкачкой виртуальной памяти системой.

Подведение итогов статьи:

По умолчанию куча больших объектов никогда не сжимается.Сжатие LOH может повысить производительность вашего собственного процесса и ускорить распределение больших объектов.Самое главное, что это позволяет другим процессам использовать больше оперативной памяти.Но у этого есть цена: сжатие LOH не является незначительным.Вот почему поведение по умолчанию - не сжимать его.Вы должны измерить плюсы и минусы и найти подходящую стратегию для запуска уплотнения: как каждые XX минут.

Теперь я объясню, почему это почти ложь.Вам необходимо прочитать эту статью, объясняющую, как управлять виртуальной памятью: Физическая и виртуальная память в Windows 10 .

Если некоторые блоки внутри LOH свободны, то к ним никогда не будет доступа.Таким образом, система способна перемещать эти блоки из оперативной памяти.Каждый активный (= используемый) блок в LOH, используемый истинным объектом, имеет размер> 85k.Размер страницы составляет 4 КБ (как в 32-битной, так и в 64-битной Windows): каждая из этих страниц может быть перемещена из ОЗУ.Простые рассуждения могут показать вам, что доля свободного пространства в LOH, который не может быть перемещен из ОЗУ, всегда мала.Либо у вас есть большие свободные блоки, а затем большая часть их страниц может быть перемещена из ОЗУ, либо у вас есть небольшие свободные блоки, и тогда их размер меньше по сравнению с используемыми блоками.В обоих случаях у вас мало свободного места в LOH, которое не может быть перемещено из ОЗУ.

Я проверял это.Я написал процесс создания фрагментированного LOH размером 10 ГБ, в котором активен только 1% (100 МБ) чередующихся активных блоков по 1 МБ со свободными блоками по 100 МБ.Только этот 1% памяти активно использовался для вычислений.На моем 16 ГБ ноутбуке я мог без проблем запустить три из этих процессов.Они не были медленными.Когда первый запустился, система дала ему рабочий набор 10 ГБ.Когда начался второй процесс, этот рабочий набор был сокращен без существенного влияния на скорость любого из этих процессов.То же самое для третьего.Через несколько минут рабочий набор каждого процесса составил 100 МБ, как и ожидалось.Только их виртуальная память была 10 ГБ.

Круизная скорость каждого процесса была довольно оптимальной.Но система должна была записать тезисы ГБ на диск.Это действительно замедляет запуск процесса.Это заняло время и ресурсы.Файл подкачки растет.Сжатие LOH каждого процесса было бы лучшей стратегией.Так что да, сжатие LOH лучше, но стандартная стратегия системы довольно хороша.Могут быть некоторые более тонкие проблемы: что происходит, когда вы повторно используете свободный блок, который был перемещен на диск: нужно ли системе читать его из файла?

Существует также практическая проблема, не связанная с производительностью.Когда вы работаете в компании, выполняющей сотни процессов на сотнях машин, вы хотите отслеживать и обнаруживать потенциальный переполнение ОЗУ.При использовании фрагментированных куч измерение размера рабочего набора вводит в заблуждение.И .NET не предоставляет легкий доступ к «общему размеру достижимых объектов».Поэтому, когда вы видите процесс, «использующий» 10 ГБ (размер рабочего набора), вы не знаете, действительно ли нужны эти 10 ГБ или нет.Сжатие LOH помогает сделать индикатор «размер рабочего набора» практически пригодным для использования.

Примечание: этот код используется для моих экспериментов:

public static class ExampleFragmentation
{
    public static void Main()
    {
        var mega = 1024 * 1024;
        var smallArrays = new int[100][];
        var largeArrays = new int[100][];
        for (int i = 0; i < 100; i++)
        {
            smallArrays[i] = CreateArray(mega);
            largeArrays[i] = CreateArray(100 * mega);
        }
        largeArrays = null;

        while (true)
        {
            DateTime start = DateTime.Now;
            long sum = 0;
            for (int i = 0; i < 100; i++)
                foreach (var array in smallArrays)
                    foreach (var element in array)
                        sum += element;
            double time = (DateTime.Now - start).TotalSeconds;
            Console.WriteLine("sum=" + sum + "  " + time + " s");
        }
    }

    private static int[] CreateArray(int bytes)
    {
        var array = new int[bytes / sizeof(int)];
        for (int i = 0; i < array.Length; i++)
            array[i] = 1;
        return array;
    }
}
0 голосов
/ 18 мая 2018

В современных ОС вы не выделяете ОЗУ 1 .Вы (Ваш процесс) выделяете в своем собственном адресное пространство.То, как ОС создает резервные копии (когда это необходимо) с помощью физической оперативной памяти, в значительной степени прозрачно.

И то, что вы сделали в вашем адресном пространстве, совершенно не имеет отношения к другим процессам.

См. Также: провокационно названный Раймонд Чен Это глупое адресное пространство 2

Может ли система действительно переместить неиспользуемую оперативную память на диск?

Это не вопрос «используемой» или «неиспользованной» оперативной памяти.Когда OS 3 заканчивается физическими страницами, он будет определять страницы, которые нужно удалить, используя некоторую подходящую стратегию (например, Least недавно использованный - это простой способ разобраться).Затем он должен решить, что делать со страницей.

Если ему повезет, выбранная страница либо подкреплена изображением файла (например, его частью исполняемого файла), либо не изменилась с момента последней записи на диск.Если это так, он может удалить страницу без каких-либо дополнительных операций ввода-вывода.Если не повезет, он запланирует ввод-вывод, а затем продолжит поиск страниц для освобождения.

Он делает это все время 4 .И это также делает другие вещи, такие как использование неиспользуемых страниц в качестве кеша файловой системы.

Единственный раз, когда у вас возникает реальная проблема, это когда общая сумма всех страниц, которые активно отработано (сумма рабочего набора каждого процесса) больше, чем количество страниц оперативной памяти, которые обычно доступны процессам.В этот момент у вас возникнут проблемы, поскольку система постоянно записывает страницы на диск и извлекает их.Но на этом этапе GC почти наверняка не поможет, поскольку мы знаем , что все эти страницы активно работают с ними - все они содержат достижимые объекты.


1 Есть способы запросить адресное пространство, которое всегда поддерживается реальной ОЗУ и никогда не меняется местами, но это не то, что обычно делается, и вам нужно сознательно изо всех сил стараться, чтобы это произошло.

2 Я знаю, что это риф на политическую цитату, но это не значит, что все читатели здесь обязательно поймут это, и некоторые люди в прошлом чувствовали, что я рекомендую эту статью на самом деле я буквально называя их глупыми.

3 Я пытаюсь быть здесь общим, но понимаю, что я могу отклониться от того, что "любая" ОС сделает с тем, что конкретно делает Windowsздесь.

4 PDC10: раскрыты тайны управления памятью Windows: часть вторая

...