Here be dragons: Управление памятью в Windows как оно есть [2/3]


    Каталог:
    Один
    Два
    Три

    Оказывается длинные опусы нужно разбивать. А я то думал «многосерийные» топики публикуют исключительно для зарабатывания рейтинга :-)

    Продолжу с места в карьер, так как где разбилось — там разбилось, а писать дополнительные введения к каждой серии выше моих сил.


    Немного о том, как страницы попадают из рабочих наборов в эти самые списки.
    Попадают разными способами. Один уже рассмотрен: кто-то явно вызвал EmptyWorkingSet для процесса. Это происходит нечасто. Обычно же это случается при помощи так называемого тримминга (trimming).

    Когда система приближается к одному из установленных лимитов на свободную память, она начинает эту память освобождать. Во первых система находит процессы, максимально превысившие свой лимит на размер рабочего набора. Для этих процессов запускается процесс «старения» страниц (aging), для определения какие из страниц меньше всего используются. После этого, самые старые страницы «подрезаются» в standby или modified список.

    Из той же лекции:


    На диаграмме видно еще Delete page, которая происходит когда приложение просто освобождает выделенную память — с содержимым этих страниц попросту уже ничего нельзя делать, потому как по всем правилом оно не валидно и даже если новая память будет выделена по тому же адресу — это должна быть новая память.

    Pagefile


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

    Миф: Для повышения производительности нужно уменьшать количество обращений к пейджфайлу.
    На самом деле: Для повышения производительности нужно уменьшать количество обращений К ДИСКУ. Пейджфайл является почти таким же файлом как и остальные.

    Миф: Винда использует пейджфайл, даже если свободной памяти еще завались.
    На самом деле: В пейджфайл страница может попасть только из modified списка. В modified список — при подрезке редко используемых страниц у разросшихся приложений. После того, как страница сброшена, она остается в standby списке и перечитываться не будет. Память никогда не берется из standby списка, если еще есть free или zeroed (то есть кешированные данные никогда не выбрасываются, если еще есть страницы вообще без данных). Standby список имеет 8 уровней приоритета (которыми до некоторой степени может управлять как само приложение, так и Superfetch, осуществляющий динамическое управление приоритетами страниц на основе анализа реального использования файлов/страниц), если не остается вообще никакого выбора — винда первым делом выбрасывает кеш самого низкого приоритета.
    Вот пример получасовой работы в обычном режиме:

    Прошу отметить, что файлы отсортированы по названию и между kernel.etl и «Program Files» должен был бы быть pagefile.sys.

    Миф: Но винда сама признается, что использует пейджфайл.
    На самом деле: Рассмотрено выше. Чаще всего речь идет о Commit Charge, который можно назвать «использованием», но совершенно не в том, смысле в котором это обычно принято понимать. В большинстве случаев при отсутсвии необходимости, приватные страницы (подлежащие сбросу в пейджфайл) будут сидеть в modified списке (даже если попадут туда) практически неограниченно долго.

    Миф: Отключение пейджфайла улучшает производительность системы.
    На самом деле: В редких случаях, приложение, которое злоупотребляет памятью и не понижает приоритет страниц для своих потоков может привести к понижению отзывчивости, однако в подавляющем большинстве случаев производительность только повышается за счет выгрузки неиспользуемого «хлама» в чулан и использовании освободившегося места для хранения более актуальных данных (тем самым снижая общее количество обращений к диску).

    Приоритеты памяти и ввода/вывода


    Чем ниже I/O приоритет потока, выполняющего запись/чтение, тем меньше он мешает нормальной работе (в целом, как и случае с приоритетами потоков используется round robin алгоритм для операций, ожидающих с наивысшим приоритетом, при этом небольшая часть пропускной способности отдается операциям с низким приоритетом в целях борьбы со starvation — на русский переводится не совсем адекватно). Запустите встроенный дефрагментатор. Resource Monitor покажет 100% загрузку диска, однако система при этом если и теряет в отзывчивости, то на глаз я этого заметить не могу.
    Про приоритеты памяти я уже упоминал. Независимо от i/o приоритета, существует page приоритет (Page Priority). Каждая физическая страница в системе (а если точнее, то данные, которые она содержит в каждый момент времени) имеет приоритет. Когда страница перемещается в Standby list она попадает в один из восьми отдельных списков, соответствующий ее приоритету. Данные с более высоким приоритетом не могут быть замещены данными с более низким.

    Prefetch и Superfetch


    Prefetch появился в XP и является способом ускорить запуск приложений. Вот утилита, позволяющая просмотреть содержимое pf файлов. Собственно говоря там находятся имена и смещения файлов, к которым соответствующее приложение обращается в первые несколько (кажется 10) секунд после запуска. Так как запуск зачастую сопровождается бешенным чтением данных с диска, то упорядочивание этих чтений уменьшает количество head seek-ов и тем самым ускоряет запуск. Работает из службы SysMain. Помимо префетча и суперфетча этот сервис отвечает еще за ReadyBoot (который помогал ускорять загрузку в одном из предыдущих постов), ReadyBoost (штука довольно бесполезная на системах с большим количеством ОЗУ, но очень полезная на low-end системах) и ReadyDrive (это такой ReadyBoost, но с гарантией, что «флешка» не будет выниматься между перезагрузками — позволяет сильно ускорить основные операции не прибегая к полной замене HDD на SSD — используя так называемые гибридные или H-HDD: скорость SSD по цене HDD).

    С суперфетчем все несколько сложнее. Мало кто понимает его назначение, но каждый норовит обвинить этот сервис в использовании памяти во время Idle и в чтении «чего то» с диска. Для начала чтение:

    Осуществляется с background приоритетом и практически незаметно при использовании. Если раздражает мигание светодиода — его можно заклеить изолентой. Более того, это чтение загружает кеш нужными данными (можно посмотреть на увеличение standby после загрузки/просыпания даже при том, что пользователь не делает никаких активных операций с диском). Эти данные загруженные сейчас с низким приоритетом и с хорошим упорядочением, потом сохранят несколько секунд и бешенное перемещение головок при старте какого нибудь приложения. Речь идет чаще всего о загрузке данных на 6-7 уровни приоритетов (да, I/O операции с низким приоритетом используются для загрузки страниц в Standby списки высоких уровней), которые могут быть вытеснены только в самом крайнем случае, когда памяти не хватает уже ни на что.

    Память этот сервис использует для хранения истории обращений к диску/страницам памяти. Периодически (в Idle) он выделяет больше для того, чтобы произвести анализ этих данных и построить долгосрочный план действий (а также бутплан на следующую загрузку). Кроме того, он производит динамическое перераспределение приоритетов страниц. Вот например, что происходит на моей домашней машине, на которой я частенько пользуюсь дотнетом (в виде powershell):

    Там в списке предствлены страницы с приоритетами от 1 до 6 (7 — это специальный приоритет, который никогда не меняется). А вот свежеустановленная виртуальная машина, на которой powershell был запущен раз в жизни за несколько секунд до этого:

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

    Видно, что все страницы понизили свой приоритет.

    Копирование больших файлов


    Здесь все просто. Запускаем копирование исошника. Видим, что копирование производится с нормальным I/O приоритетом:

    Page priority потока я не сохранил, но могу с большой долей уверенности сказать, что там тоже «норма» — то есть 5. Значит ли это, что копирование файлов рано или поздно повыкидывает из кеша всех остальных? Проверим:

    Все закешировалось с приоритетом 2 даже несмотря на то, что чтение осуществлялось с приоритетом 5. В чем же дело? А вот в чем:


    Для операций копирования используется флаг FILE_FLAG_SEQUENTIAL_SCAN, который приводит к понижению приоритета кеша по сравнению с базовым, к использованию только одного VACB для кеширования и к более агрессивному read-ahead-у.
    Share post
    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More
    Ads

    Comments 34

      +4
      ахаха, фотка в начале из моего сайта )))

      статью читаю…
        –1
        поставил плюс только из-за картинки, т.к. сразу вспомнил детство с паяльником (как раз всякую такую схемотехнику паял) ))))
      • UFO just landed and posted this here
          +2
          А в первой статье — вообще схема триггера на лампах. Зато ОЗУ
            +23
            Ну а что вы хотели? =) Картинка для привлечения. МОжно былоб и голую бабу залепить. Хотя для некоторых 565РУ5Г лучше голой бабы
              0
              даешь 2 в 1: микросхемы верхом на сиськах!
          0
          Основательно…
            +1
            Во первых система находит процессы, максимально превысившие свой лимит на размер рабочего набора. Для этих процессов запускается процесс «старения» страниц (aging), для определения какие из страниц меньше всего используются.
            Вот это ново для меня. Я считал, что все страницы равноправны и у них всегда считается время последнего доступа, а оказывается это механизм для самых жадных.

            Standby список имеет 8 уровней приоритета (которыми до некоторой степени может управлять как само приложение, так и Superfetch, осуществляющий динамическое управление приоритетами страниц на основе анализа реального использования файлов/страниц), если не остается вообще никакого выбора — винда первым делом выбрасывает кеш самого низкого приоритета.
            Здесь я еще раз хотел бы подчеркнуть, что данный механизм появился только в висте. До этого винда спокойно выкидывала данные приложения, оставляя в памяти кеш дисковой системы.
              +3
              > Здесь я еще раз хотел бы подчеркнуть, что данный механизм появился только в висте.
              Да. Только это было 5 лет назад — эпоха по айтишным меркам.
              0
              РУ5 — вспмннил детство! Первая попавшая в мои руки с паяльником динамическая память! ;) Был в то время такой компьютер — ЮТ-88. Там модуль динамической памяти собирался на РУ5 и мультиплекирование регенерации было сделано на ПЗУ (а-ля ПЛИС в итоге). Ностальгия однако!
                +1
                Задачка по теме а-ля «check your knowledge» ;)
                Есть компьютер с Windows 7 x64, 4G RAM, 128G SSD. Page-файл по умолчанию имеет размер 4G.
                Докупается еще 4G RAM в целях увеличения производительности. Теперь 8G RAM и page-файл тоже 8G.
                Вопрос, что сделать с page-файлом, и, главное, почему?
                — оставить как есть
                — отключить
                — уменьшить
                — другой вариант
                  0
                  Ах, да, важный момент: page-файл ни разу не увеличивался, т.е. 8G виртуальной памяти всегда хватало на любую работу.
                    –2
                    Отвечу тебе поговоркой: «Работает нормально? НЕ ЛЕЗЬ!»
                    +2
                    Поставьте «Указать размер вручную», далее «Исходный размер: 100М» и «Максимальный размер: 4000М». Тогда он почти всегда будет занимать 100М, а на крайний случай — увеличится.
                    +7
                    > Миф: Отключение пейджфайла улучшает производительность системы.

                    Я бы не назвал это в полной мере «мифом», все зависит от того, как именно используется компьютер. Часто бывает, что лучше уж пусть «зажравшееся» приложение немедленно умрет по нехватке памяти, чем уйдет в бесконечный своп, тем самым потянув на дно и всю систему. Поясню. Бывает так, что размер свопа не ограничен сверху (или ограничен большим числом), а то или иное приложение из-за бага начинает кушать и кушать память. В итоге все начинает настолько зверски тормозить (из-за перегруженности диска), что убить приложение удается только через 3-4 минуты. Иногда это неприемлемо.

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

                    Т.е. отключение свопа — это не мера увеличения производительности, это мера для улучшения скорости отклика в критических ситуациях.

                    Еще одна мысль. В штатном режиме работы на серверной системе своп-активности быть не должно (т.к. важна максимальная скорость отклика). Как только возникает своп-активность, вся система деградирует (обидно, если это происходит из-за какой-нибудь второстепенной ерунды, которая лучше бы просто умерла, чем кушала память). Поэтому я люблю делать так: на хост-машине оставлять своп, однако на всех виртуальных машинах — жестко ограничивать максимальный размер памяти, так, чтобы вся имеющаяся память была распределена между виртуальными машинами непротиворечиво. Тогда в случае аварии я на хост-машину всегда смогу зайти, в то время как виртуальные машины будут убивать «зажравшиеся» процессы.
                      +2
                      Согласен. Описываемый дальше случай с мюторрентом показывает, что если не сделать ничего, то все может стать плохо. С другой стороны, если уж заниматься оптимизацией производительности, то лучше насильно понизить приоритет памяти для подобного процесса (или другим способом решить проблему в приложении), чем отключать подкачку. Радует то, что подавляющему большинству приложений никаких дополнительных телодвижений делать не нужно
                      0
                      Спасибо за статью!
                      Можно поподробнее про приоритеты ввода \ вывода (в статье такая формулировка, как будто их много, а я встречал только два — нормальный и низкий).
                      А также про регулирование приоритета памяти? Не встречал такого API
                        +2
                        Приоритетов ввода/вывода пока 5:
                        typedef enum _IO_PRIORITY_HINT {
                          IoPriorityVeryLow    = 0,
                          IoPriorityLow        = 1,
                          IoPriorityNormal     = 2,
                          IoPriorityHigh       = 3,
                          IoPriorityCritical   = 4,
                          MaxIoPriorityTypes   = 5 
                        } IO_PRIORITY_HINT;
                        


                        Называется хинтом, потому что это просто число, ассоциированное с запросом на ввод вывод. Файловая система реализует приоретизацию по своему
                          0
                          А я правильно понимаю, что SetThreadPriority(h, THREAD_MODE_BACKGROUND_BEGIN) устанавливает приоритет в минимальный, а SetThreadPriority(h, THREAD_MODE_BACKGROUND_END) возвращает IoPriorityNormal?

                          Также интересно, влияет ли еще на какие-то приоритеты THREAD_MODE_BACKGROUND_BEGIN — в документации упомянуто про «resource scheduling priorities», что намекает на несколько уровней приоритета
                            +1
                            Он снижает все три приоритета: приоритет (который приоритет на использование CPU), приоритет ввода/вывода и приоритет памяти

                            Нормальный приоритет процессора — 8, ввода/вывода — 2 (Normal), памяти — 5

                            Приоритет ввода/вывода можно менять не только для потока, но и для отдельных файлов, приоритет процессора — довольно известная штука и уже практически не вызывает вопросов, а вот с приоритетом памяти есть определенные проблемы. THREAD_MODE_BACKGROUND_BEGIN/END — это единственное публичное API, которое мне известно, и позволяет переключать приоритет между уровнями 5 и 1. Суперфетч имеет свое API (через один из information class-ов в NtSetSystemInformation), которое позволяет более тонко контроллировать приоритет памяти (и более того, перемещать уже загруженные страницы между приоритетами), но ни официальной, ни даже неофициальной документации на это я не встречал.
                        0
                        >Миф: Винда использует пейджфайл, даже если свободной памяти еще завались.
                        На самом деле: В пейджфайл страница может попасть только из modified списка. В modified список — при подрезке редко используемых страниц у разросшихся приложений...


                        Скажите, это справедливо для всей линейки Windows или начиная с определённой версии?
                          0
                          Для всех (начиная с NT3.51 общие принципы не менялись). В первую очередь используются страницы без данных: Free и Zeroed. Если эти списки пусты — принимается решение о том, какую страницу из Standby списка взять. Standby — это кеш общего назначения, там хранится как кеш обычных файлов, так и кеш пейджфайла (фактически здесь даже кавычки не нужны, по сути это и есть кеш содержимого пейджфайла), а переиспользоваться может любая из этих страниц. При последующем обращении к данным, которые были там закешированы — эти данные придется заново читать с диска.

                          С другой стороны, ЗАПИСЬ в пейджфайл иногда (редко) может происходить даже при наличии свободных страниц. Если приложение серьезно превысило свой MaxWorkingSet и его приватные страницы были подрезаны в modified список, система может решить, что хорошо бы эти данные сбросить на диск. При этом следует понимать, что данные оказываются и в пейджфайле и в физической памяти. Если приложение потребует свои данные обратно — обработчик page fault-а просто найдет соответствующую страницу в standby.
                            0
                            Тогда объясните мне, если всё так, как Вы говорите, то почему получается так, что «имеем машину с WinXP с 4-мя гигабайтами памяти, запускаем VS 2003, немного работаем, запускаем какой-нибудь ФФ, минут 20 неспешно браузим (в пределах 5-6 табов, не больше), переключаемся обратно в VS — и мучительно ждём, когда же будет отрисовано окно VS (под весёлый треск жёсткого диска)»?
                            Никакого сверх тяжёлого проекта загружено не было, сама VS, как я уже сказал, 2003-го года, так что подозревать её в чрезмерных аппетитах я бы не стал, ФФ забить несколько гигов не успел бы чисто физически. В чём может быть дело? Сценарий воспроизводим в 100% случаев.
                              0
                              Каким образом определяете наличие памяти во free или zeroed списках?
                              Как я уже сказал, если уже ВСЯ память забита кешем — каким нибудь из кешей придется пожертвовать. И в случае с VS это не обязательно приватная память из пейджфайла — вполне могут быть выброшены и страницы образов — грузит то она их достаточно.

                              Попробуйте запустить xperf/procmon перед разворачиванием VS.

                              А вообще совет: переходите уже на современную систему. 4 Гб более чем достаточно для комфортной работы
                                +1
                                >Попробуйте запустить xperf/procmon перед разворачиванием VS.

                                Попробую.

                                >А вообще совет: переходите уже на современную систему.

                                На домашнем компе я давно перешёл на современную систему (не из линейки Windows).
                                На рабочем не получится: современная система не поддерживает определённый специализированный софт, необходимый для работы (даже в режиме совместимости), поэтому политика компании — Windows XP на рабочих машинах.
                                  0
                                  > не из линейки Windows
                                  Линукс (и прочие *nix, за исключением разве что MacOSX, хотя как раз FreeBSD часть является там самой устаревшей) не является современной, ага. Зная Вас, я сначала написал эту ремарку в прошлом комментарии, но потом опять таки, зная Вас, убрал чтоб не начинать этих танцев — да я вообще линукс не упоминал.
                                    +1
                                    Зная Вас, я ожидал подобного комментария, и именно с этой целью было написано уточнение в скобках.
                                    Спасибо.
                              0
                              Если приложение потребует свои данные обратно — обработчик page fault-а просто найдет соответствующую страницу в standby.

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

                                0
                                Каким образом, если фоновая запись в своп идёт с самым низким приоритетом?
                                  0
                                  А в XP вообще были приоритеты при работе с диском?
                                    0
                                    Нет, это появилось в висте. Возможно, низкий процессорный приоритет фоновой подкачки может на это повлиять, но эффект будет меньше, чем непосредственно у приоритетов дисковых операций.
                                    Впрочем, это не относится к самому алгоритму использования подкачки.
                                      0
                                      Зато это относится к файлу подкачки. Файл есть — все дисковые операции тормозят и компьютер «висит». Файла нет — компьютер работает шустро.
                                        0
                                        Подкачка юзается не настолько часто, чтобы тормозить всё на свете. К сожалению, на реальной машине проверить не могу, у меня 24ГБ памяти и подкачка отключена, но на виртуалках проблем со слишком агрессивным использованием подкачки я не встречал. Само собой всё это относится к XP, которая у меня стоит в 64 битной редакции.
                            0
                            Символичная картинка — «советские микросхемы — У.Г.» )))

                            Only users with full accounts can post comments. Log in, please.