Welcome to TechNet Blogs Sign in | Join | Help

Преодолевая границы Windows: процессы и потоки

Это четвертая статья из серии "Преодолевая границы Windows", в рамках которой я рассказываю об ограничениях, существующих для фундаментальных ресурсов в Windows. На сей раз, я собираюсь обсудить с вами ограничение на максимальное количество потоков и процессов, поддерживаемое Windows. Здесь я кратко опишу различие между потоком и процессом, ограничение потока опроса (от англ. survey thread), после чего мы поговорим об ограничениях, связанных с процессами. В первую очередь я решил рассказать об ограничениях потоков, так как каждый активный процесс имеет, по крайней мере, один поток (процесс, который завершился, но ссылка на который хранится в обработчике, предоставленном другим процессом, не имеет ни одного потока), так что ограничения процессов напрямую зависят от основных ограничений, связанных с потоками.


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


Преодолевая границы Windows: физическая память
Преодолевая границы Windows: виртуальная память
Преодолевая границы Windows: выгружаемый и невыгружаемый пулы


Процессы и потоки
Процесс Windows по своей сути является контейнером, в котором хранится код команд из исполняемого файла. Он представляет собой объект процесса ядра и Windows использует этот объект процесса и связанные с ним структуры данных для хранения и сопровождения информации об исполняемом коде приложения. Например, процесс имеет виртуальное адресное пространство, в котором хранятся его частные и общие данные и в которое отображаются исполняемый образ и связанные с ним библиотеки DLL. Windows с помощью инструментов диагностики записывает информацию об использовании процессом ресурсов для обеспечения учета и выполнения запросов и регистрирует ссылки процесса на объекты операционной системы в таблице дескриптора процесса. Процессы работают с контекстом безопасности, именуемом маркером, который идентифицирует учетную запись пользователя, группы учетной записи и привилегии, назначенные процессу.


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


Ограничения потоков
Помимо основной информации о потоке, включая данные о состоянии регистров ЦП, присвоенный потоку приоритет и информацию об использовании потоком ресурсов, у каждого потока есть выделенная ему часть адресного пространства процесса, называемая стеком, которую поток может использовать как рабочую память по ходу исполнения кода программы, для передачи параметров функций, хранения локальных переменных и адресов результатов работы функций. Таким образом, чтобы избежать нерациональной траты виртуальной памяти системы, первоначально распределяется только часть стека, или же часть ее передается потоку, а остаток просто резервируется. Поскольку стеки в памяти растут по нисходящей, система размещает так называемые "сторожевые" страницы (от англ. guard pages) памяти вне выделенной части стека, которые обеспечивают автоматическое выделение дополнительной памяти (называемой расширением стека), когда она потребуется. На следующей иллюстрации показано, как выделенная область стека углубляется и как сторожевые страницы перемещаются по мере расширения стека в 32-битном адресном пространстве:

image_4

Структуры Portable Executable (PE) исполняемых образов определяют объем адресного пространства, которое резервируется и изначально выделяется для стека потока. По умолчанию компоновщик резервирует 1Мб и выделяет одну страницу (4Кб), но разработчики могут изменять эти значения либо меняя значения PE, когда они организуют связь со своей программой, либо путем вызова для отдельного потока функции CreateTread. Вы можете использовать утилиту, такую как Dumpbin, которая идет в комплекте с Visual Studio, чтобы посмотреть настройки исполняемой программы. Вот результаты запуска Dumpbin с опцией /headers для исполняемой программы, сгенерированной новым проектом Visual Studio:

 

Переведя числа из шестнадцатеричной системы исчисления, вы можете увидеть, что размер резерва стека составляет 1Мб, а выделенная область памяти равна 4Кб; используя новую утилиту от Sysinternals под названием MMap, вы можете подключиться к этому процессу и посмотреть его адресное пространство, и тем самым увидеть изначально выделенную страницу памяти стека процесса, сторожевую страницу и остальную часть зарезервированной памяти стека:

image_6 

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


Ограничения 32-битных потоков
Даже если бы у процесса вообще не было ни кода, ни данных и все адресное пространство могло бы быть использовано под стеки, то 32-битный процесс с установленным по умолчанию адресным пространством в 2 б мог бы создать максимум 2048 потоков. Вот результаты работы программы Testlimit, запущенной в 32-битной Windows с параметром -t (создание потоков), подтверждающие наличие этого ограничения:

image_8

Еще раз, так как часть адресного пространства уже использовалась под код и начальную динамическую память, не все 2Гб были доступны для стеков потоков, так что общее количество созданных потоков не смогло достигнуть теоретического предела в 2048 потоков.


Я попробовал запустить Testlimit с дополнительной опцией, предоставляющей приложению расширенное адресное пространство, надеясь, что если уж ему дадут больше 2Гб адресного пространства (например, в 32-битных системах это достигается путем запуска приложения с опцией /3GB или /USERVA для Boot.ini, или же эквивалентной опцией BCD на Vista и позднее increaseuserva), оно будет его использовать. 32-битным процессам выделяется 4Гб адресного пространства, когда они запускаются на 64-битной Windows, так сколько же потоков сможет создать 32-битный Testlimit, запущенный на 64-битной Windows? Если основываться на том, что мы уже обсудили, ответ должен быть 4096 (4Гб разделенные на 1Мб), однако на практике это число значительно меньше. Вот 32-битный Testlimit, запущенный на 64-битной Windows XP:

image_10

Причина этого несоответствия кроется в том факте, что когда вы запускаете 32-битное приложение на 64-битной Windows, оно фактические является 64-битным процессом, которое выполняет 64-битный код от имени 32-битных потоков, и потому в памяти для каждого потока резервируются области под 64-битные и 32-битные стеки потоков. Для 64-битного стека резервируется 256Кб (исключения составляют ОС, вышедшие до Vista, в которых исходный размер стека 64-битных потоков составляет 1Мб). Поскольку каждый 32-битный поток начинает свое существование в 64-битном режиме и размер стека, который ему выделяется при старте, превышает размер страницы, в большинстве случаев вы увидите, что под 64-битный стек потока выделяется как минимум 16Кб. Вот пример 64-битных и 32-битных стеков 32-битного потока (32-битный стек помечен как "Wow64"):

 

image_12

32-битный Testlimit смог создать в 64-битной Windows 3204 потока, что объясняется тем, что каждый поток использует 1Мб + 256Кб адресного пространство под стек (повторюсь, исключением являются версии Windows до Vista, где используется 1Мб+ 1Мб). Однако, я получил другой результат, запустив 32-битный Testlimit на 64-битной Windows 7:

 

image_14

Различия между результатами на Windows XP и Windows 7 вызвано более беспорядочной природой схемы распределения адресного пространства в Windows Vista, Address Space Layout Randomization (ASLR), которая приводит к некоторой фрагментации. Рандомизация загрузки DLL, стека потока и размещения динамической памяти, помогает улучшить защиту от вредоносного ПО. Как вы можете увидеть на следующем снимке программы VMMap, в тестовой системе есть еще 357Мб доступного адресного пространства, но наибольший свободный блок имеет размер 128Кб, что меньше чем 1Мб, необходимый для 32-битного стека:

image_16

Как я уже отмечал, разработчик может переустановить заданный по умолчанию размер резерва стека. Одной из возможных причин для этого может быть стремление избежать напрасного расхода адресного пространства, когда заранее известно, что стеком потока всегда будет использоваться меньше, чем установленный по умолчанию 1Мб. PE-образ Testlimit по умолчанию использует размер резерва стека в 64Кб, и когда вы указываете вместе параметром -t параметр -n, Testlimit создает потоки со стеками размером в 64Кб. Вот результат работы этой утилиты на системе с 32-битной Windows XP и 256Мб RAM (я специально провел этот тест на слабой системе, что подчеркнуть данное ограничение):

 

image_18

Здесь следует отметить, что произошла другая ошибка, из чего следует, что в данной ситуации причиной является не адресное пространство. Фактически, 64Кб-стеки должны обеспечить приблизительно 32 000 потоков (2Гб/64Кб = 32768). Так какое же ограничение проявилось в данном случае? Если посмотреть на возможных кандидатов, включая выделенную память и пул, то никаких подсказок в нахождении ответа на этот вопрос они не дают, поскольку все эти значения ниже их пределов:

image_20

Ответ мы можем найти в дополнительной информации о памяти в отладчике ядра, который укажет нам искомое ограничение, связанное с доступной резидентной памятью, весь объем которой был исчерпан:

 

image_26

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


Базовый стек ядра занимает 12Кб в 32-битной Windows и 24Кб в 64-битной Windows. 14225 потоков требуют для себя приблизительно 170Мб резидентной памяти, что точно соответствует объему свободной памяти на этой системе с выключенным Testlimit:

image_28

Как только достигается предел доступной системной памяти, многие базовые операции начинают завершаться с ошибкой. Например, вот ошибка, которую я получил, дважды кликнув на ярлыке Internet Explorer, расположенном на рабочем столе:

 

image_81

Как и ожидалось, работая на 64-битной Windows с 256Мб RAM, Testlimit смог создать 6600 потоков - примерно половину от того, сколько потоков эта утилита смогла создать в 32-битной Windows с 256Мб RAM - до того, как исчерпалась доступная память:

image_30

Причиной, по которой ранее я употреблял термин "базовый" стек ядра, является то, что поток, который работает с графикой и функциями управления окнами, получает "большой" стек, когда он исполняет первый вызов, размер которого равен (или больше) 20Кб на 32-битной Windows и 48Кб на 64-битной Windows. Потоки Testlimit не вызывают ни одного подобного API, так что они имеют базовые стеки ядра.
Ограничения 64-битных потоков


Как и у 32-битных потоков, у 64-битных потоков по умолчанию есть резерв в 1Мб для стека, но 64-битные имеют намного больше пользовательского адресного пространства (8Тб), так что оно не должно стать проблемой, когда дело доходит до создания большого количества потоков. И все же очевидно, что резидентная доступная память по-прежнему является потенциальным ограничителем. 64-битная версия Testlimit (Testlimit64.exe) смогла создать с параметром -n и без него приблизительно 6600 потоков на системе с 64-битной Windows XP и 256Мб RAM, ровно столько же, сколько создала 32-битная версия, потому что был достигнут предел резидентной доступной памяти. Однако, на системе с 2Гб оперативной памяти Testlimit64 смог создать только 55000 потоков, что значительно меньше того количества потоков, которое могла бы создать эта утилита, если бы ограничением выступила резидентная доступная память (2Гб/24Кб = 89000):

image_22

В данном случае причиной является выделенный начальный стек потока, который приводит к тому, что в системе заканчивается виртуальная память и появляется ошибка, связанная с нехваткой объема файла подкачки. Как только объем выделенной памяти достигает размера оперативной памяти, скорость создания новых потоков существенно снижается, потому что система начинает "пробуксовывать", ранее созданные стеки потоков начинают выгружаться в файл подкачки, чтобы освободить место для стеков новых потоков, и файл подкачки должен увеличиваться. С включенным параметром -n результаты те же, поскольку таким же остается начальный объем выделенной памяти стека.


Ограничения процессов
Число процессов, поддерживаемых Windows, очевидно, должно быть меньше, чем число потоков, потому как каждый процесс имеет один поток и сам по себе процесс приводит к дополнительному расходу ресурсов. 32-битный Testlimit, запущенный на системе с 64-битной Windows XP и 2Гб системной памяти создает около 8400 процессов:

 

image_32

Если посмотреть на результат работы отладчика ядра, то становится понятно, что в данном случае достигается ограничение резидентной доступной памяти:

 

image_36

Если бы процесс использовал резидентную доступную память для размещения только лишь стека потока привилегированного режима, Testlimit смог бы создать намного больше, чем 8400 потоков на системе с 2Гб. Количество резидентной доступной памяти на этой системе без запущенного Testlimit равно 1,9Гб:

image_38

Путем деления объема резидентной памяти, используемой Testlimit (1,9Гб), на число созданных им процессов получаем, что на каждый процесс отводится 230Кб резидентной памяти. Так как 64-битный стек ядра занимает 24 Кб, мы получаем, что без вести пропали примерно 206Кб для каждого процесса. Где же остальная часть используемой резидентной памяти? Когда процесс создан, Windows резервирует достаточный объем физической памяти, чтобы обеспечить минимальный рабочий набор страниц (от англ. working set). Это делается для того, чтобы гарантировать процессу, что любой ситуации в его распоряжении будет достаточное количество физической памяти для сохранения такого объема данных, который необходим для обеспечения минимального рабочего набора страниц. По умолчанию размер рабочего набора страниц зачастую составляет 200Кб, что можно легко проверить, добавив в окне Process Explorer столбец Minimum Working Set:

image_40

Оставшиеся 6Кб - это резидентная доступная память, выделяемая под дополнительную нестраничную память (от англ. nonpageable memory), в которой хранится сам процесс. Процесс в 32-битной Windows использует чуть меньше резидентной памяти, поскольку его привилегированный стек потока меньше.


Как и в случае со стеками потока пользовательского режима, процессы могут переопределять установленный для них по умолчанию размер рабочего набора страниц с помощью функции SetProcessWorkingSetSize. Testlimit поддерживает параметр -n, который, в совокупности с параметром -p, позволяет устанавливать для дочерних процессов главного процесса Testlimit минимально возможный размер рабочего набора страниц, равный 80Кб. Поскольку дочерним процессам нужно время, чтобы сократить их рабочие наборы страниц, Testlimit, после того, как он больше не сможет создавать процессы, приостанавливает работу и пробует ее продолжить, давая его дочерним процессам шанс выполниться. Testlimit, запущенный с параметром -n на системе с Windows 7 и 4Гб RAM уже другого, отличного от ограничения резидентной доступной памяти, предела - ограничения выделенной системной памяти:

image_24

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

 

image_34

До запуска Testlimit средний уровень выделенного объема памяти был равен приблизительно 1,5Гб, так что потоки заняли около 8Гб выделенной памяти. Следовательно, каждый процесс потреблял примерно 8 Гб/6600 или 1,2Мб. Результат выполнения команды !vm отладчика ядра, которая показывает распределение собственной памяти (от англ. private memory) для каждого процесса, подтверждает верность данного вычисления:

image_61

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


Сколько процессов и потоков будет достаточно?
Таким образом, ответы на вопросы "сколько потоков поддерживает Windows?" и "сколько процессов вы можете одновременно запустить на Windows?" взаимосвязаны. Помимо нюансов методов, по которым потоки определяют размер их стека и процессы определяют их минимальный рабочий набор страниц, двумя главными факторами, определяющим ответы на эти вопросы для каждой конкретной системы, являются объем физической памяти и ограничение выделенной системной памяти. В любом случае, если приложение создает достаточное количество потоков или процессов, чтобы приблизиться к этим пределам, то его разработчику следует пересмотреть проект этого приложения, поскольку всегда существуют различные способы достигнуть того же результата с разумным числом процессов. Например, основной целью при масштабировании приложения является стремление сохранить число выполняющихся потоков равным числу ЦП, и один из способов добиться этого состоит в переходе от использования синхронных операции ввода/вывода к асинхронным с использованием портов завершения, что должно помочь сохранить соответствие числа запущенных потоков с числом ЦП.

Posted by abeshkov | 0 Comments

Преодолевая ограничения Windows: дескрипторы

Это уже пятая статья из моей серии публикаций "Преодолевая границы Windows", в которых я рассказываю о максимальном значении и объеме ресурсов, которыми управляет Windows, таких как физическая память, виртуальная память, процессы и потоки:


Преодолевая границы Windows: Физическая память
Преодолевая границы Windows: Виртуальная память
Преодолевая границы Windows: Выгружаемый и невыгружаемый пулы
Преодолевая границы Windows: Процессы и потоки


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


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


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


Дескрипторы и объекты

Ядро Windows, работающее в привилегированном режиме, реализованное в образе %SystemRoot%\System32\Ntoskrnl.exe, состоит из различных подсистем, таких как диспетчер памяти, диспетчер процессов, диспетчер ввода/вывода, диспетчер конфигураций (системный реестр), которые является частями исполнительной системы. Каждая из этих подсистем вместе с диспетчером объектов определяет один или более типов для представления ресурсов, которые они выделяют приложениям. Например, диспетчер конфигураций определяет объект "ключ" (Key) для представления открытого ключа системного реестра; диспетчер памяти объект "Секция" (Section) для общей памяти; исполнительная система определяет объекты "семафор" (Semaphore), "мутант" (Mutant, внутреннее название для мьютекса) и "синхронизация событий" (Event synchronization) (эти объекты представляют собой оболочку для структур данных, определенных подсистемой Ядро операционной системы); диспетчер ввода/вывода определяет объект "файл" (File) для представления открытых экземпляров ресурсов драйверов устройств, которые включают в себя файлы файловой системы; и, наконец, диспетчер процессов создает объекты "поток" (Thread) и "процесс" (Process), о которых я рассказывал в своей последней публикации из данной серии. Каждый релиз Windows вводит новые типы объектов, в том числе и Windows 7, которые принес с собой в общей сложности 42 новых типа. Определенный в вашей системы объекты вы можете увидеть при помощи утилиты Winobj от Sysinternals, запущенной с правами администратора, открыв директорию ObjectTypes пространства имен Object Manager:

image_40

Когда приложение желает получить управление над одним из этих ресурсов, оно сначала должно вызвать соответствующий API, чтобы создать или открыть ресурс. Например, функция CreateFile открывает или создает файл, функция RegOpenKeyEx открывает ключ реестра, а функция CreateSemaporeEx открывает или создает семафор. Если такая функция успешно выполняется, Windows размещает дескриптор в таблице дескрипторов процесса приложения и возвращает значение этого дескриптора, которое приложение обрабатывает неявно, однако фактически речь идет об индексе возвращенного дескриптора в таблице дескрипторов.
Имея в своем распоряжении дескриптор, приложение делает запросы и управляет объектом, передавая значение дескриптора в такие функции API, как ReadFile, SetEvent, SetThreadPriority и  MapViewOfFile. Система может организовать поиск объекта, к которому обращается дескриптор путем индексирования таблицы дескрипторов, чтобы определить местонахождения соответствующей дескриптору записи, которая содержит указатель на объект. Запись дескриптора также хранит информацию об операциях, которые стали доступны процессу, когда он открыл объект, что позволяет системе быть уверенной в том, что процесс не сможет выполнять над объектом операции, на которые у этого процесса нет разрешения. Например, если процесс успешно открыл файл для чтения, то запись дескриптора выглядела примерно так:

image_42

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


Максимальное число дескрипторов
Чтобы исследовать первое ограничение вы можете воспользоваться инструментальным средством Testlimit, которое я уже использовал в рамках данной серии статей для того, чтобы опытным путем изучить ограничения на ресурсы системы. Его можно скачать на странице Windows Internals здесь. Для определения количества дескрипторов, которое может создать процесс, Testlimit используется с параметром -h, который указывает ему создать столько дескрипторов, сколько возможно. Это достигается путем создания объекта event с помощью функции CreateEvent и последующего неоднократного дублирования возвращаемого системой дескриптора с помощью функции DuplicateHandle. Используя дублирование, Testlimit избегает необходимости создания новых объектов и все ресурсы, потребляемые этим инструментов, расходуются для записей таблицы дескрипторов. Вот результат работы Testlimit с ключом -h в 64-битной системе

image_2

Этот результат, однако, не отображает общее количество дескрипторов, которые может создать процесс, поскольку системные библиотеки DLL открывают различные объекты во время инициализации процесса. Общее число дескрипторов процесса вы можете увидеть, добавив соответствующую колонку в диспетчере задач или Process Explorer. Общее цифра для Testlimit в данном случае равна 16’771’680:

 

image_14

Когда вы запускаете Testlimit на 32-битной системе, число дескрипторов будет немного отличаться:

image_8

Общее число дескрипторов также другое, 16,744,448:

 

image_6

Чем обуславливаются эти различия? Ответ состоит в том, что исполнительная система, ответственная за управление таблицей дескрипторов, устанавливает ограничение на количество дескрипторов для каждого процесса, а также на размер записи в таблице дескрипторов. Здесь мы имеем дело с одним из тех редких случаев, когда Windows устанавливает жесткое ограничение на использование ресурса, так что в данном случае исполнительная система определяет число 16,777,216 (16*1024*1024) как максимальное количество дескрипторов, которое может быть выделено процессу. Любой процесс, которые имеет более десяти тысяч дескрипторов одновременно в какой-либо момент времени, весьма вероятно имеет либо серьезные недочеты, допущенные при его проектировании, или утечку дескрипторов. Так что предел в 16 миллионов дескрипторов практически недостижим и призван помочь предотвратить утечку памяти, вызванную вмешательством в работу процесса со стороны остальной системы. Чтобы понять причину того, почему число, отображаемое в диспетчере задач, отличается от жестко установленного максимума, требуется рассмотреть то, каким образом исполнительная система организовывает таблицу дескрипторов.


Запись таблицы дескрипторов должна иметь достаточный размер для того, чтобы хранить маску прав доступа и указатель на объект. Маска доступа является 32-битной, но размер указателя, очевидно, зависит от того, является система 32-битной или 64-битной. Следовательно, запись дескриптора занимает 8 байт на 32-битной Windows и 12-байт на 64-битной Windows. 64-битная Windows дополняет структуры данных записи дескриптора до 64-битных границ, так что 64-битная запись дескриптора фактически занимает 16 байт. Вот определение записи дескрипторов на 64-битной Windows, отображенное в отладчике ядра с помощью команды dt (dump type)

image_18

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


Исполнительная система размещает таблицы дескрипторов в блоки, имеющие размер страницы, которые она делит на записи таблицы дескрипторов. Это означает, что страница, которая занимает 4096 байт и на системах x86, и на системах x64, может сохранить 512 записей в 32-битной Windows и 256 записей в 64-битной Windows. Исполнительная система определяет максимальное число страниц, которые она может выделить под записи дескрипторов, путем деления жестко установленного максимума (16,777,216) на число записей дескрипторов на странице; для 32-битной Windows это число равно 32,768, а для 64-битной Windows - 65,536. Поскольку исполнительная система использует первую запись на каждой странице для своей собственной идентификационной информации, действительное количество дескрипторов, доступных для процесса, следует получать, вычитая из 16,777,216 полученные выше числа, что объясняет результаты, полученные при запуске Testlimit: 16,777,216 - 65,536 = 16,711,680 и 16,777,216 - 32,768 = 16,744,488.


Дескрипторы и выгружаемый пул
Вторым ограничением, касающимся дескрипторов, является объем памяти, требуемой для хранения таблицы дескрипторов, который исполнительная система выделяет из выгружаемого пула. Исполнительная система для отслеживания выделяемых ею под таблицы дескрипторов страниц использует трехуровневую схему, подобную той, которую используют модули управления памятью (MMU) процессора для руководства трансляциями виртуальных адресов в физические. Мы уже рассматривали с вами организацию нижнего и среднего уровней, которые фактически хранят в себе записи таблицы дескрипторов. Верхний уровень служит в качестве указателей на таблицы среднего уровня и включает в себя 1024 записи на страницу в 32-битной Windows. Отсюда следует, что общее количество страниц, требуемых для хранения максимального числа дескрипторов для 32-битной Windows можно вычислить как 16,777,216/512*4096, что равно 128 Мб. Это совпадает с показателями использования Testlimit выгружаемого пула, которые показывает диспетчер задач:

image_12

В 64-битной версии Windows на верхнем уровне содержится 256 указателей на страницу. Это означает в общем для размещения полной таблицы дескрипторов используется 256 Мб выгружаемого пула (16,777,216/256*4096). Правильность данных вычислений подтверждается показателями использования Testlimit выгружаемого пула на 64-битной Windows:

image_14

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


Утечки дескрипторов
Для процесса, допускающего утечку дескрипторов характерно то, что число потерянных дескрипторов постоянно возрастает. Причина этого кроется в том, что утечка дескрипторов очень коварна - в отличие от случая с Testlimit, который создавал дескрипторы для одного и того же объекта, процесс, имеющий утечку дескрипторов, вероятнее всего теряет вместе с ними и объекты. Например, если процесс создает события, но не может закрыть их, он создает утечку как записей дескрипторов, так и объектов событий. Объекты "event" располагаются в невыгружаемом пуле, так что данная утечка затронет в дополнение к выгружаемому пулу и невыгружаемый пул.
Вы можете визуально определить объекты, доступ к которым потерял процесс, используя представление дескрипторов в Process Explorer, поскольку там новые дескрипторы выделены зеленым, а закрытые - красным; если вы увидите много зеленых записей при малом количестве красных, значит вы, скорее всего, столкнулись с утечкой. Чтобы увидеть подобное выделение дескрипторов Process Explorer в действии, вы можете открыть процесс командной строки и, выбрав этот процесс в Process Explorer, перейти к просмотру дескрипторов, после чего следует сменить текущую директорию в командной строке. Дескриптор старой рабочей директории подсветится красным, а новой - зеленым:

image_20

По умолчанию Process Explorer показывает только дескрипторы, которые указывают на объекты, имеющие имена, что означает, что вы не увидите всех дескрипторов процесса, если не включите опцию "Show Unnamed Handles and Mappings" в меню View. Вот некоторые безымянные дескрипторы из таблицы дескрипторов командной строки:

image_32

Как и в случае с большинством других ошибок, только разработчик кода, из-за которого происходит утечка, может исправить это. Если вы обнаружили утечку у процесса, который состоит из нескольких компонентов или расширений, например, Explorer, Service Host или Internet Explorer, то главный вопрос состоит в том, какая из этих частей ответственна за утечку. Определение такого компонента позволило бы вам избежать появления проблемы, отключив или удалив проблемное расширение, проверить его на наличие обновлений, исправляющих эту ошибку или сообщить о ней разработчику.


К счастью, Windows включает в себя средство отслеживания дескрипторов, которое вы можете использовать для установления факта утечки и определения ответственного за эту утечку программного обеспечения. Оно работает с каждым процессом в отдельности и активируется исполнительной системой для записи активности стека каждый раз, когда какой-либо дескриптор создается или закрывается. Вы можете воспользоваться этим инструментом или при помощи утилиты Application Verifier, которую можно бесплатно скачать с сайта Microsoft, или воспользовавшись отладчиком Windows (Windbg). Если вы хотите, чтобы система проследила за активностью дескрипторов процесса, начиная с его запуска, то вам нужно использовать Application Verifier. В остальных случаях вам нужно использовать отладчик и команду !htrace, чтобы увидеть информацию об активности процесса.


Чтобы продемонстрировать отслеживание активности в действии, я запустил Windbg и подключился к командной строке, которую я запустил ранее. Чтобы включить отслеживание дескрипторов, я ввел команду !htrace с ключом -enable:

image_44

Я позволил процессу продолжать работу и снова сменил директорию. После этого я переключился обратно на Windbg, остановил выполнение процесса и запустил команду htrace без параметров, которая выдает список всех открытых и закрытых операций, которые выполнил процесс, начиная с предыдущего запуска команды !htrace с параметром snapshot или с того момента, когда была включена запись активности дескрипторов. Вот результаты работы этой команды для той же сессии отладчика:

 

image_36

Здесь перечислены события, начиная с самой последней операции, так что, если читать снизу, мы увидим, что командная строка открыла дескриптор 0xb8, затем закрыла его, потом открыла дескриптор 0x22c и в конце закрыла дескриптор 0xec. Process Explorer отметил бы дескриптор 0x22c зеленым и 0xec красным, если бы он был обновлен после смены директории, но, по всей вероятности, не увидел бы 0xb8, если бы обновление не произошло между открытием и закрытием этого дескриптора. Стек для открытия 0x22c показывает, что данная операция стала результатом выполнения командной строкой (cmd.exe) своей функции ChangeDirectory. Если добавить в Process Explorer колонку Handle, она подтвердит, что новый дескриптор - 0x22c:

 

image_38

Если вы ищите только утечки, то вам нужно использовать !htrace с параметром -diff, которая показывает только новые дескрипторы, начиная с последней засечки или с начала запуска отслеживания активности. Как и ожидалось, в результате выполнения этой команды мы видим только дескриптор 0x22c:

 

image_34

Прекрасным источником советов о том, как можно устранить утечки дескрипторов является интервью инженера по технической поддержке Microsoft Джеффа Дэйли (Jeff Dailey) для Channel 9.


В следующий раз я рассмотрю ограничения, установленные для таких основанных на дескрипторах ресурсов, как объекты GDI и USER. Дескрипторы этих ресурсов управляются подсистемой Windows, отличной от исполнительной системы, а потому используют другие ресурсы и имеют другие ограничения.

Posted by abeshkov | 0 Comments

Дело о временных профилях реестра

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

 

image_6

 

Вследствие этого Windows создала временный профиль для процесса входа пользователя в систему. Профиль пользователя располагается в директории %UserProfile%, в которую приложения сохраняют файлы конфигураций и данных (для каждого пользователя они свои), а также файл ветви реестра в директории %UserProfile%\Ntuser.dat, который процесс Winlogon загружает во время входа пользователя в систему. Приложения сохраняют настройки пользователя в ветви системного реестра путем вызова функций, обращающихся к корневой директории HKEY_CURRENT_USER (HKCU). Факт потери пользователем доступа к их профильным файлам перевел рассматриваемую проблему в разряд критических, поскольку каждый раз, когда это случалось, пользователь терял все свои настройки, а также доступ к файлам, хранившимся в его профильной директории. В большинстве случаев пользователи обращались в службу поддержки компании, где их просили попытаться перезагружать компьютер и входить в систему до тех пор, пока проблема не решится сама по себе.


Как обычно бывает в таких случаях, первым делом специалисты службы поддержки Microsoft спрашивали пользователей о конфигурации системы, установленном программном обеспечении и обо всех недавних изменениях, которые их компания вносила в их систему. В ходе анализа собранных данных был обнаружен тот факт, что на всех системах, которые были подвержены этой проблеме, недавно был произведен апгрейд до новой версии ICA-клиента от Citrix Corporation, приложения для работы с удаленным рабочим столом. Microsoft связалась с поддержкой Citrix, чтобы узнать, известно ли им о каких-либо ошибках, связанных с новым клиентом. Они ответили на этот вопрос отрицательно, но при этом сказали, что займутся расследованием этого дела.

 

Неуверенные в том, что причиной возникновения проблемы с профилями пользователей является обновление ICA-клиента, поддержка Microsoft проинструктировала своего клиента о том, как включить функцию ведения лога процессов работы с профилем. Сделать это можно внеся изменения в соответствующий ключ реестра, как описано в этой статье базы знаний. Клиент внес указанные изменения в свои системы и вскоре после этого получил новые сообщения от пользователя, столкнувшегося с проблемой, связанной с профилем. Они сделали копию лога профиля %SystemRoot%\Debug\UserMode\Userenv.log и отослали ее в Microsoft. Лог не смог дать ответ почему случается данная проблема, однако содержал в себе одну важную подсказку: он указывал на то, что профиль пользователя не смог загрузиться из-за ошибки 32, которой является ошибка ERROR_SHARING_VIOLATION:

image_2

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


А тем временем все больше клиентов по всему миру стало обращаться в Microsoft и Citrix с той же самой проблемой, и каждый из них тоже недавно устанавливал новый ICA-клиент. Тогда поддержка Cintrix сообщила, что они подозревают, что ошибка совместного доступа могла быть вызвана одним из процессов ICA-клиента - Ssonvr.exe. Во время инсталляции ICA-клиент регистрирует библиотеку Network Provider DLL (Pnsson.dll), которую вызывает Windows Multiple Provider Notification Application (%SystemRoot%\System32\Mpnotify.exe) во время загрузки системы. Сам Mpnotify.exe запускается процессом Winlogon во время входа в систему. Библиотека Citrix запускает процесс Ssonvr.exe асинхронно процессу входа пользователя в систему:

image_15 

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


Microsoft создала версию Winlogon и ядра, собирающих дополнительную диагностическую информацию и попыталась воспроизвести проблему в лаборатории, на системах имеющих ту же конфигурацию, что и компьютеры клиента, но все безуспешно. Клиент даже не смог еще раз вызвать проблему на измененном образе Windows, что произошло, скорее всего, потому, что образ изменил время реакции системы настолько, что это помогло избежать проблемы. В этой ситуации один из инженеров поддержки Microsoft предложил, чтобы клиент фиксировал все последствия процесса входа в систему с помощью Process Monitor.


Есть несколько способов настроить Process Monitor для запись операций входа в систему: первый подразумевает использование Sysinternals PsExec для ее запуска в нулевой сессии, чтобы утилита смогла "пережить" выход и последующий вход в систему; второй заключается в применении функции создания лога загрузки для фиксации активности в системе, начиная с ранних этапов загрузки и включая вход в систему. Инженер выбрал второй способ. Он сказал клиенту запустить Process Monitor на одной из систем, на которой постоянно сталкивались с рассматриваемой проблемой, выбрать опцию Enable Boot Logging в меню Options, и произвести перезагрузку, выполняя все ее шаги до тех пор, пока проблема не проявится. Эта процедура вносит изменения в драйвер Process Monitor, чтобы утилита запускалась на ранних этапах загрузки и регистрировала активность в файл %SystemRoot%\Procmon.pmb. Как только пользователь столкнулся бы с проблемой, он должен был снова запустить Process Monitor, что привело бы к окончанию процесса записи лога, и Process Monitor преобразовал бы загрузочный лог в стандартный файл лога Process Monitor.


После нескольких попыток пользователь успешно повторил ощибку и зафиксировал загрузочный файл лога, который затем отправил в Microsoft. Инженеры поддержки Microsoft просмотрели этот лог и обнаружили ошибку совместного доступа, возникшую, когда Winlogon пытался загрузить ветвь системного реестра:

image_8

Исходя из операций, непосредственно предшествующих появлению ошибки, было очевидно, что Ssonsvr.exe был тем процессом, для которого открывалась ветвь. Вопрос состоял в том, почему Ssonsvr.exe открывал ветвь системного реестра? Чтобы дать на него ответ инженеры обратились к функциям Process Monitor по отслеживанию активности стека. Process Monitor фиксирует состояние стека вызовов для каждой операции. Просматривая стек вызовов, зачастую вы можете определить корень операции, что не всегда можно определить, зная лишь то, какой процесс эту операцию запустил. Например, стек может показать вам, что библиотека DLL, загруженная в процесс, выполняет операцию, и, если у вас правильно настроено отображение символов и вызов происходит в образе Windows или другом образе, для которого проведена настройка символов, он даже покажет вам названия ответственных за это функций.


Стек Ssonsvr.exe, открытый из файла Ntuser.dat, показал, что не Ssonsvr.exe был ответственен за вызов операции, а Windows Logical Prefetcher:

image_10

Впервые появившийся в Windows XP Logical Prefetcher представляет собой компонент ядра системы, который отслеживает первые десять секунд запуска процесса, записывая директории и части файлов, к которым обратился данный процесс за это время, в файл в директории %SystemRoot%\Prefetch. Для того, чтобы несколько исполняемых файлов, имеющие одинаковые имена, но расположенные в разных директориях, имели свой собственный prafetch-файл, Logical Prefetcher дает этому файлу имя, составляемое из имени исполняемого образа и хэша, полученного на основе пути хранения этого исполняемого образа (например, NOTEPAD.EXE-D8414F97.pf). Вы можете увидеть файлы и директории, которые записал Logical Prefetcher во время последнего запуска приложения, используя утилиту Sysinternals Strings для сканирования prefetch-файла:

 

strings <prefetch file>

 

Во время следующего запуска приложения Logical Prefetcher, выполняющийся в контексте первого потока процесса, просматривает prefetch-файл. Если таковой существует, он открывает каждую директорию, присутствующую в списке, чтобы перенести метаданные директории в память, если там их еще нет. Затем Logical Prefetcher отображает в память каждый файл, перечисленный в prefetch-файле, и устанавливает ссылки на те их части, к которым приложение обращалось во время последнего запуска, таким образом, они так же загружаются в память. Logical Prefetcher может ускорить запуск приложения, потому что генерирует большие, последовательные потоки ввода/вывода, вместо того, чтобы заниматься организацией доступа к маленьким случайным частям данных файла, что обычно делает приложение во время запуска.


Обнаружение связи между Logical Prefetcher и проблемой профилей поставило перед инженерами поддержки новые вопросы. Почему Logical Prefetcher подгрузил файл ветви пользователя в контексте Ssonsvr.exe, тогда как сам Ssonsvr.exe никогда не обращается к профилям системного реестра? Чтобы получить ответ на этот вопрос, инженеры поддержки Microsoft обратились к команде разработчиков Logical Prefetcher. Прежде всего, разработчики отметили, что чтение из системного реестра Windows XP производится из операций ввода/вывода кэшированных файлов с использованием системной памяти, что означает, что поток опережающего чтения Cache Manager активно считывает части ветви. Так как этот поток опережающего чтения выполняется в процессе System и Logical Prefetcher связывает активность этого процесса с запускающимся в настоящее время процессом, эта последовательность задержек в процессе запуска и последующей активности во время загрузки и входа в систему могла послужить причиной того, что Logical Prefetcher получил доступ к ветви в качестве части процесса запуска Ssonsvr.exe. Если бы при следующих загрузке и входе в систему порядок этих событий немного изменился, то Winlogon столкнулся бы с Logical Prefetcher, что мы и видим в записанном файле лога.


Logical Prefetcher выполняется прозрачно по отношению к другой активности в системе, однако его ссылки на файл могут привести к ошибкам совместного доступа, в данном случае на Windows XP (на серверных системах Logical Prefetcher занимается только подготовкой запуска системы, причем делает он это строго перед продолжением выполнения загрузочных процессов и синхронизирован с ними). По этой причине на системах Windows Vista и Windows 7 Logical Prefetcher использует драйвер минифильтра файловой системы Fileinfo (%SystemRoot%\System32\Drivers\Fileinfo.sys) для отслеживания потенциальных ошибок совместного доступа и предотвращения их появления, для чего он останавливает вторую операцию, желающую получить доступ к файлу, которым в данный момент пользуется Logical Prefetcher, до тех пор, пока он его не закроет.


Теперь, когда проблема была решена, Microsoft и Citrix задумались над тем, какие действия предпринять клиентам, чтобы избежать появления ошибки, на то время, пока Citrix работала над обновлением для ICA-клиента, которое предотвратило бы ошибку совместного доступа. Первым вариантом является отключение функции подгрузки файлов для приложения, вторым - написание скрипта для процесса выхода из системы, который удалял бы prefetch-файлы Ssonsvr.exe. Citrix опубликовала свои рекомендации в этой статье, а Microsoft - в этой статье. Обновление для ICA-клиента, которое стало доступно несколькими днями позже, изменило время запуска библиотеки DLL провайдера сети на 10 секунд после запуска Ssonsvr.exe, до того, как контроль будет передан Mpnotify.exe. Поскольку Winlogon ожидает завершения Mpnotify.exe для того, чтобы выйти до того, как пользователь войдет в систему, Logical Prefetcher не будет относить запросы на доступ к файлам куста пользователя, принадлежащие Winlogon, к процессу запуска Ssonsvr.exe.


Как я уже сказал во введении, я нахожу этот случай особенно интересным, поскольку в нем проявляются малоизвестная функция Process Monitor - ведение лога загрузки системы - и полезность показателей активности стека для анализа первопричины проблемы - два ключевых инструментальных средства из арсенала для решения проблем, которые каждый может использовать. Он также показывает нам то, как успешная диагностика может помочь придумать временный обход проблемы в ситуациях, когда решения не существует или вам приходится ждать, пока вендор его предоставит. Еще одна проблема, успешно решенная при помощи Process Monitor. Пожалуйста, продолжайте присылать мне скриншоты и файлы логов для решенных вами проблем.

Posted by abeshkov | 0 Comments

Дело о медленной демонстрации

Несколько недель назад я впервые участвовал в презентации на конференции Microsoft Teched перед аудиторией в 5000 человек. Билл Вегте (Bill Veghte), старший вице-президент Microsoft по продажам Windows, вел эту презентацию и делал обзор новых возможностей Windows 7 для конечных пользователей, Иэйн Макдональд (Iain McDonald), главный менеджер Windows Server, демонстрировал новые функциональные возможности Hyper-V и Windows Server 2008 R2, а я рассказывал об ориентированных на IT-профессионалов расширениях Windows 7 и Microsoft Desktop Optimization Pack (MDOP).


Я демонстрировал такие функции, как BitLocker To Go, возможности удаленного управления PowerShell v2, возможности PowerShell по созданию скриптов для объектов групповых политик, Microsoft Enterprise Desktop Virtualization (MEDV) и то, как комбинация App-V, перемещаемых профилей пользователя и перенаправление папок позволяют менять аппаратную часть ПК с минимальным временем простоя. Я особо отметил тот факт, что мы прилагаем все усилия, чтобы гарантировать, что исправления, касающиеся совместимости приложений (мы их называем прокладками - shims), которые IT-профессионалы разработали для Vista, работали на Windows 7. Я также продемонстрировал работу новой функции Windows 7, носящей название AppLocker, которая помогает IT-профессионалам ограничить спектр программного обеспечения, которое пользователи могут запустить на корпоративных компьютерах, при этом данная особенность поддерживает гибкую систему правил, согласно которым определяется такое ПО.


За несколько недель до проведения этой презентации я работал с Джейсоном Лезнеком (Jason Leznek), отвечавшим за часть презентации, адресованной IT-профессионалам, для изучения приложений, с помощью которых я буду проводить презентацию и организовывать демо-показы. Мы проводили пробные прогоны по сценарию, настраивая демонстрацию и создавая переходы, урезая информационное наполнение презентации, чтобы уложиться во временные рамки, отведенные моему выступлению, и сокращали мою речь, чтобы она была сосредоточена главным образом на преимуществах, которые предоставляют новые технологии. Для демонстрации про совместимость приложений мы решили использовать стандартную программу, используемую в Microsoft, которая называется Stock Viewer и относится к той группе присутствующего сегодня на корпоративном рынке программного обеспечения, которое несовместимо с Vista и Windows 7 и не может быть запущено на этих операционных системах без стороннего вмешательства. В моей демонстрации я запускал Stock Viewer на Windows 7 и показывал, что при работе программы постоянно появляются сообщения о каких-то неопределенных ошибках, вызванных совместимостью:

image_28

Далее я показывал, как я устанавливал прокладку совместимости приложения, позволяющую ему корректно работать на Vista и успешно запускал это приложение.


Мы также хотели показать, как AppLocker облегчает процесс создания правил, позволяющих запускать программное обеспечение на основании информации об издателе или о версии, если это ПО имеет цифровую подпись. Первоначально мы планировали показать AppLocker после демонстрации, посвященной совместимости приложений, и использовать в качестве примера Adobe Acrobat Reader в качестве приложения, часто используемого в компаниях. Мы несколько раз прогоняли эту презентацию, однако нам казалось, что переходы были несколько неуклюжими, и потому я предложил, чтобы мы поставили демонстрацию о AppLocker перед демонстрацией со Stock Viewer. Я мог запускать Stock Viewer на основании правила AppLocker и после показать, как прокладка помогает правильно работать данному приложению, используя обе демонстрации.


Я вернулся в свой офис, поставил для Stock Viewer цифровую подпись Sysinternals и отослал его Джейсону. Несколько часов спустя он сообщил мне через электронную почту, что что-то не так с демонстрационной системой, потому как Stock Viewer, который до этого запускался мгновенно, теперь тратил на запуск около минуты. Близилось начало TechEd и он был в панике, поскольку мы уже должны были делать демонстрацию. Ранее я слышал о том, что .NET инициирует проверку цифровой подписи при загрузке приложений, имеющих цифровую подпись, так что мое первое подозрение пало именно на это. Я попросил Джейсона зафиксировать результаты работы Process Monitor и он отослал мне их несколькими минутами позже.


После того, как я открыл протокол, первое, что я сделал, - это отфильтровал события для StockViewer.exe, чтобы найти его первые операции, и установил параметры быстрого фильтра:

image_6

После этого я посмотрел на время первого события, 2:27:20, и последнего события, 2:28:32, которые различались с минутной задержкой, которую и наблюдал Джейсон. Я просмотрел весь список и увидел много записей, относящихся к шифрованию ключей реестра и папок файловой системы, а также настоек TCP/IP, но я знал, что должен быть какой-то один пункт, который бы объяснил столь серьезную задержку при запуске. Я просмотрел протокол сначала и нашел временной промежуток примерно в 10 секунд после 2:27:22:

 

image_4_s

Непосредственно перед этим операции были связаны с Rasadhlp.dll,  DLL отвечающей за работу с сетью, а немногим ранее с ключами реестра Winsock, а сразу после десятисекундной задержки - с доступом к зашифрованным ключам реестра. Создавалось впечатление, что система не была подключена к Интернету и что около десяти секунд система ожидала отклика сети. Я начал просматривать список дальше, ожидая увидеть подобные задержки, и обнаружил 12-секундный интервал:

image_8_s

И на этот раз работа с сетью до и связанная с шифрованием активность после. Следующий 12-секундный перерыв был идентичен предыдущему:

image_10_s

В итоге следующие несколько промежутков были очень похожи на предыдущие два. В каждом случае непосредственно перед паузой появлялась запись, относящаяся к HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings\Connections, так что я установил фильтр по этому ключу и увидел шесть промежутков ровно по 12 секунд каждый:

image_18

В сумме - 6 раз по 12 секунд - они давали ту задержку, которую увидел Джеймс. Далее я захотел убедиться, что эти повторяющие попытки получить доступ к сети были вызваны проверкой цифровой подписи, и потому я начал проверять стеки различных событий, выбирая их и нажимая Ctrl-K для открытия диалогового окна свойств стека. Стек событий, связанных с настройками Интернет-подключения, показал, что причиной был как раз процесс шифрования:

image_25

Чтобы окончательно удостовериться, я захотел убедиться, что в конечном итоге за эти проверки отвечал именно .NET. Я повторно просмотрел лог, и увидел записи, подтверждающие то, что Stock Viewer является .NET-приложением:

image_16

Я также обратил внимание на стеки некоторых ранних событий, связанных с шифрованием ключей реестра и увидел, что это были вызовы из рабочей среды .NET процедуры WinVerifyTrust, которая является функцией Windows, позволяющей провести проверку цифровой подписи файла, который провел несколько попыток доступа в Интернет:

image_24

После того, как я удостоверился, что причиной задержки старта приложения является .NET, который, видя, что Stockviewer.exe имеет цифровую подпись, начинает проверять, не отозван ли соответствующий сертификат, я начал искать в сети способы обойти проверку .NET, так как я знал, что вероятнее всего машины, с помощью которых будет проводиться презентация, во время выступления не будут подключены к Интернету. По прошествии некоторого времени я нашел эту статью:

image_20

В статье указаны все те же признаки, которые видели мы, и отмечается, что .NET 2.0, который я использовал для работы с Stock Viewer (это я узнал на основании путей к DLL-файлам, которые фигурировали в логе), поддерживает способ отключения обязательной проверки цифровых подписей: для этого необходимо создать файл конфигураций в папке с исполняемым файлом с таким же именем, как и сам файл .exe, за исключением расширения ".config" (например, StockViewer.exe.config), содержащий следующий XML-код:

Код:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
      <runtime>
              <generatePublisherEvidence enabled="false"/>
      </runtime>
</configuration>


Примерно через 15 минут после того, как я получил сообщение Джеймса, я послал ему свой ответ с объяснением своих выводов и файлом конфигурации. Вскоре после этого, он прислал мне подтверждение, что задержки исчезли и выразил свое изумление, что я так быстро определил проблему и нашел решение. Для него, возможно, это выглядело как волшебство, однако я просто использовал основные методики решения проблем с помощью Process Explorer и сеть для поиска решения. В результате наша демонстрация на TechEd с переходом между AppLocker и совместимостью приложений возымели большой успех.

Posted by abeshkov | 0 Comments

Преодолевая ограничения Windows: выгружаемый и невыгружаемый пулы

В предыдущих статьях из цикла "Преодолевая границы Windows" я рассказал о двух основных ресурсах системы: физической памяти и виртуальной памяти. В этот раз я собираюсь поведать о двух фундаментальных ресурсах ядра, выгружаемом (от англ. paged) и невыгружаемом (от англ. nonpaged) пулах, которые основаны на первых двух ресурсах и которые имеют непосредственное влияние на многие другие ограничения системных ресурсов, включая максимальное число процессов, объектов синхронизации и дескрипторов.


Выгружаемый и невыгружаемый пулы представляют собой ресурсы памяти, которые операционная система и драйвера устройств используют для сохранения своих структур данных. Диспетчер пула работает в режиме ядра, используя области системного виртуального адресного пространства (которое описано в статье про виртуальную память) для памяти, которую он выделяет. Диспетчер пула ядра также работает с диспетчером C-runtime и диспетчером динамической памяти Windows, которые выполняются в пользовательском режиме. Поскольку минимальный размер выделяемой виртуальной памяти кратен размеру системной страницы (4KB для систем x86 и x64), эти вспомогательные диспетчеры памяти делят большие выделяемые участки памяти на маленькие части, чтобы память не расходовалась впустую.


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


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


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


Выгружаемый пул
Выгружаемый пул, с другой стороны, получил свое название потому, что Windows может записать данные, которые он хранит, в файл подкачки, позволяя тем самым использовать физическую память, которая при этом освобождается, в других целях. Как и в случае с виртуальной памятью пользовательского режима, когда драйвер или система ссылается на выгружаемый пул памяти, которых находится в файле подкачки, и диспетчер памяти считывает данные обратно в физическую память. Самым большим потребителем выгружаемого пула, по крайней мере в Windows Vista и более поздних ОС, обычно является системный реестр, так как ссылки на ключи и другие структуры данных реестра хранятся в выгружаемом пуле. Структуры данных, которые представлены в виде отображаемых на память файлов, называемых секциями, также хранятся в выгружаемом пуле.


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


Просмотр информации об использовании выгружаемого и невыгружаемого пулов.
Есть три счетчика, показывающих информацию об использовании пула:

  • Пул невыгружаемых байтов;
  • Пул выгружаемых байтов (виртуальный размер выгружаемого пула);
  • Пул выгружаемых резидентных байтов.


Однако, не существует каких-либо счетчиков производительности (performance counters) указывающих максимальный размера этих пулов. Такие данные можно получить воспользовавшись командой отладчика ядра !vm, но, чтобы использовать отладчик ядра в режиме локальной отладки в Windows Vista и более поздних версиях системы, вам необходимо загрузить систему в режиме отладки, в котором отключено воспроизведение MPEG2.


Так что вместо этого для просмотра текущего и максимального выделенного размера пула лучше использовать Process Explorer. Чтобы увидеть максимум, вам нужно настроить Process Explorer на использование файлов отладочных символов операционной системы. Во-первых, установите последнюю версию пакета Debugging Tools for Windows. Затем запустите Explorer и откройте диалоговое окно Symbol Configuration из меню Options и укажите в нем путь на файл dbghelp.dll в установочной директории Debugging Tools for Windows, после чего задайте в поле Symbol path сервера символов Microsoft:

 

image_4

После того, как вы настроите символы, откройте диалоговое окно System Information (кликните на пункте System Information меню View или нажмите Ctrl+I), чтобы увидеть информацию о пуле в секции Kernel Memory. Вот как это выглядит в системе Windows XP с 2Гб памяти:

image_6

32-x битная Windows XP с 2-мя Гб ОЗУ

Ограничения на размер невыгружаемого пула.

Как я упоминал в предыдущей статье, в 32-битной Windows системное адресное пространство по умолчанию составляет 2Гб. По сути, это значение устанавливает границу для невыгружаемого пула (или любого типа системной виртуальной памяти) в 2Гб, но он должен делить это пространство с другими типами ресурсов, такими как собственно ядро, драйвера устройств, системные входы таблицы страниц (PTE) и представления системных файлов.


До Vista диспетчер памяти в 32-битных Windows вычислял, сколько адресного пространства назначать каждому типу ресурсов во время загрузки. Его формулы принимали во внимание множество факторов, главным из которых являлось количество физической памяти в системе. Объем адресного пространства, выделяемого им для невыгружаемого пула, начинается с 128Мб для системы с 512Мб системной памяти и достигает 256Мб для систем с 1Гб памяти и более. На системе, загруженной с опцией /3GB, которая расширяет адресное пространство пользовательского режима до 3Гб за счет адресного пространства ядра, максимальный размер невыгружаемого пула составляет 128Мб. На предыдущем снимке Process Explorer отображается максимум в 256Мб на системе Windows XP с 2Гб системной памяти, загруженной без флага /3GB.


Диспетчер памяти в Windows Vista и в более поздних версиях системы, включая Server 2008 и Windows 7 (32-битной версии Windows Server 2008 R2 нет) не реализует статическое разделение системного адресного пространства; вместо этого, он динамически назначает диапазоны адресов различным типам памяти согласно изменяющимся требованиям. Однако, он все еще назначает максимальный размер невыгружаемого пула, который основывается на количестве физической памяти, равный чуть больше чем 75% от физической памяти или двум гигабайтам, в зависимости от того, что меньше. Вот максимум для системы Windows Server 2008 с 2Гб оперативной памяти:

image_8

32-x битный Windows Server 2008 с 2-мя Гб ОЗУ

64-х битные системы Windows обладают гораздо большим адресным пространством, так что диспетчер памяти может спокойно распределять его статически, не беспокоясь о том, что какому-то типу данных не будет хватать места. 64-битная Windows XP и Windows Server 2003 устанавливают максимальный размер невыгружаемого пула немногим более 400Кб на каждый мегабайт оперативной памяти или в 128Гб, в зависимости от того, что меньше. Вот снимок из системы с 64-битной Windows XP и 2Гб памяти:

image_10

64-x битная Windows XP с 2-мя Гб ОЗУ

Диспетчеры памяти 64-битных Windows Vista, Windows Server 2008, Windows 7 и Windows Server 2008 R2, так же как и их 32-битные аналоги (за исключением Windows Server 2008 R2, у которого, как уже упоминалось ранее, нет 32-битной версии) устанавливают ограничение на размер невыгружаемого пула приблизительно в 75% от RAM, однако максимальное значение для него равно 128Гб вместо 2Гб. Вот скриншот системы с 64-битной Windows Vista с 2Гб системной памяти, для которой ограничение на размер невыгружаемого пула равно таковому для системы с 32-битной Windows Server 2008, снимок которой приведен ранее

image_12

32-x битная Windows XP с 2-мя Гб ОЗУ

И наконец, вот данное ограничение для системы с 64-битной Windows 7 с 8Гб памяти:

image_24

Вот сводная таблица ограничений на размер невыгружаемого пула для различных версий Windows:

  32-бита 64-bit
XP, Server 2003 до 1.2ГБ ОЗУ: 32-256 МБ 
> 1.2ГБ ОЗУ: 256 МБ
минимум ( ~400K/МБ ОЗУ, 128ГБ)
Vista, Server 2008,
Windows 7, Server 2008 R2
минимум ( ~75% of RAM, 2GB) минимум (~75% ОЗУ, 128ГБ)

Ограничения на размер выгружаемого пула
Ядро и драйверы устройств используют выгружаемый пул для хранения любых структур данных, которые никогда не будут вызываться изнутри DPC или ISR, или когда спинлок (spinlock) занят. Именно поэтому содержимое выгружаемого пула может либо находиться в физической памяти, либо, если алгоритмы работы диспетчера памяти решат использовать данную физическую память для других целей, быть записано в файл подкачки, откуда его, если это понадобиться, можно возвратить обратно в физическую память. Потому ограничение на размер выгружаемого пула прежде всего зависит от объема системного адресного пространства, выделяемого для выгружаемого пула диспетчером памяти.


Для 32-х битной Windows XP данный предел вычисляется исходя из того, сколько адресного пространства выделено другим ресурсам, в особенности таблице PTE, с максимальным значением в 491Мб. Для системы с Windows XP и 2Гб системной памяти данное ограничение равно 360Мб:

image_6

32-x битная Windows XP с 2-мя Гб ОЗУ

 

32-х битный Windows Server 2003 резервирует для выгружаемого пула больше места, так что верхний предел в этом случае равен 650Мб.
Так как 32-битная Windows Vista и все последующие системы реализуют динамическое адресное пространство ядра, для них данное ограничение просто установлено в 2Гб. Потому увеличение размера выгружаемого пула прекратится тогда, когда системное адресное пространство заполнится, либо когда будет достигнут установленный системой предел.


64-х битные Windows XP и Windows Server 2003 устанавливают этот максимум равным ограничению на размер невыгружаемого пула, умноженного на четыре, либо 128 Гб, в зависимости от того, что окажется меньше. Вот снимок системы с 64-битной версией Windows XP, на котором предел размера выгружаемого пула равен как раз четырем размерам невыгружаемого пула:

image_10

И наконец, 64-х битные версии Windows Vista, Windows Server 2008, Windows 7 и Windows Server 2008 R2, просто устанавливают данный максимум в 128Гб, позволяя тем самым с помощью ограничения на размер выгружаемого пула определить системное ограничение. Вот снимок системы с 64-битной Windows 7:

image_24

64-x битная Windows 7 с 8-ю Гб ОЗУ

 

Вот сводная таблица ограничений на размер выгружаемого пула для различных операционных систем:

  32-бита 64-бита
XP, Server 2003 XP: до 491МБ
Server 2003: до 650МБ
минимум ( 4 * невыгружаемого пула, 128ГБ)
Vista, Server 2008,
Windows 7, Server 2008 R2
минимум ( system commit limit, 2GB) минимум ( system commit limit, 128ГБ)

 

Тестирование ограничений на размер пула
Поскольку пулы ядра используются практически каждой операцией ядра, полное их истощение может привести к непредсказуемым результатом. Если вы хотите на своем опыте посмотреть, как ведет себя система в случае интенсивного использования пула используйте утилиту Notmyfault. У нее есть функции, которые позволяют осуществить утечку некоторого указанного пользователем объема выгружаемого или невыгружаемого пулов. Вы можете изменять этот размер по своему желанию, а после закрытия Notmyfault вся занятая этой утилитой память освобождается:

image_14

Вам не стоит запускать это приложение в своей системе, если вы не готовы к возможной потере данных, так как после того, как свободное место пула закончится, приложения и операции ввода/вывода начнут завершаться с ошибкой. Вы даже можете получить синий экран смерти (BSOD), если какой-то драйвер не сможет корректно обработать условие выгрузки из памяти (что считается ошибкой драйвера). Windows Hardware Quality Laboratory (WHQL) тестирует драйверы, используя Driver Verifier - утилиту, встроенную в Windows - чтобы убедиться в том, что они могут обрабатывать выгрузку из пула без ошибок, однако у вас могут быть установлены драйверы сторонних производителей, которые либо не прошли такое тестирование, либо имеют ошибки, которые не были обнаружены во время тестов WHQL.


Я запускал Notmyfault на множестве тестовых систем на виртуальных машинах, чтобы увидеть, как как они поведут себя и не встретятся ли с какими-нибудь системными ошибками. После того, как невыгружаемый пул на системе с 64-битной Windows XP бы исчерпан, попытка запуска командной строки завершилась следующим диалоговым окном:

image_16

В 32-битной Windows Server 2008 с уже запущенной командной строкой после того, как невыгружаемый пул был исчерпан, даже простые операции, такие как изменения текущей директории или вывод списка директорий, завершались с ошибкой:

image_18

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

image_42

Такие же ошибки возникали и в случае исчерпания выгружаемого пула. Вот результаты попытки запуска Блокнота из командной строки на системе с 32-битной Windows XP, после того как выгружаемый пул был исчерпан. Обратите внимание на то, что Windows не смогла запустить перерисовку заголовка окна, а также выдавала различные ошибки при каждой новой попытке запуска приложения:

image_20

А вот пример того, как на системе с 64-битной Windows Server 2008 после исчерпания выгружаемого пула в папке Стандартные меню Start не оказалось ни одного пункта:

image_22

На данном снимке вы можете видеть максимальный уровень занимаемой памяти (который также отображается в диалоговом окне System Infomations программы Process Explorer), который стремительно повышается по мере того, как Notmyfault совершает утечку крупных участков выгружаемого пула и достигает максимума в 2Гб на системе, работающей по управлением 32-битной версии Windows Server 2008 с 2Гб оперативной памяти:

image_26

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


Отслеживание утечек пула
В случае, если вы подозреваете наличие утечки пула и система все еще может запускать приложения, Poolmon - инструмент из набора Windows Driver Kit - покажет вам число выделенных областей и количество незанятых байтов в этих областях, разделенных по типу пула, а также теги запросов ExAllocatePoolWithTag. Различные комбинации горячих клавиш позволяют Poolmon сортировать содержимое по различным колонкам; чтобы найти выделенные участки памяти, являющие собой утечки, нажмите клавишу "b" для сортировки по байтам, или "d" для сортировки по разности между числом выделенных и свободных участков памяти. Вот снимок, демонстрирующий работу Poolmon на системе, где с помощью Notmyfault была организована утечка 14 участков памяти пула, каждый примерно по 100Мб:

image_38

После того, как вы нашли искомый тег в левой колонке (в данном случае это "Leak"), следующим шагом будет нахождение драйвера, использующего этот тег. Так как эти теги хранятся в образе драйвера, вы можете просканировать данный образ на наличие рассматриваемого тега. Утилита Strings от Sysinternals сохраняет искомые строки в указанном вами файле (искомая строка по умолчанию должна быть не короче 3-х символов, и, так как большинство образов драйверов находятся в директории %Systemroot%\System32\Drivers, вы можете открыть командную строку, изменить текущую директорию на указанную и выполнить команду "strings * | findstr <tag>". После того, как вы найдете соответствия, вы можете получить информацию о версии драйвера с помощью утилиты Sigcheck от Sysinternals. Вот как выглядит процесс поиска драйвера, использующего тег "Leak":

image_30

Если произошел сбой системы и вы подозреваете, что это виной этому истощение пула, загрузите дамп-файл этого сбоя в отладчике Windbg, который включен в состав пакета Debugging Tools for Windows, и удостоверьтесь в этом с помощью команды !vm. Вот результат запуска этой команды на системе, в которой Notmyfault исчерпал невыгружаемый пул:

image_34

Как только вы убедитесь в наличии утечки, воспользуйтесь командой !poolused, чтобы просмотреть информацию об использовании пула, как это было в Poolmon. По умолчанию эта команда выдает несортированные данные, так что используйте параметр 1 для сортировки по использованию выгружаемого пула, и 2 - для сортировки по использованию невыгружаемого пула:

image_36

Используйте утилиту Strings для поиска в дампе информации о драйвере, использующем тег, определенный вами как причина утечки.


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

 

Оригинал записи

Posted by abeshkov | 0 Comments

Дело о таинственных файлах на рабочем столе

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


Несколько дней спустя я вернулся домой с работы и моя жена встретила меня у дверей, объяснив, что проблема снова повторилась, и она оставила окно открытым, чтобы показать мне эти таинственные файлы. Я с предвкушением подошел к компьютеру и изучил ситуацию. На компьютере было открыто окно IE, развернутое на весь экран, с большим количеством открытых вкладок с открытыми письмами. На переднем плане было открыто диалоговое окно IE "Открыть файл", в котором отображался список файлов в папке Desktop, возникающее при щелчке по кнопке "Присоединить файл". Диалоговое окно выглядело следующим образом:

file

Я свернул окно IE, чтобы увидеть сам рабочий стол, который находился на фоне, и убедился, что несколько файлов, которые присутствовали в диалоговом окне, в частности, папка Maui Feb. 08 и JPG-файлы CIMG13xx, отсутствовали. Я открыл окно Windows Explorer, чтобы зайти в папку Desktop, чтобы посмотреть, будут ли видны эти файлы в проводнике, но там также ничего не было:

 

file1

Раньше я никогда с таким не сталкивался. Я знал, что это работа для Process Monitor. Так как на компьютере моей жены инструментов Sysinternals не установлено (грустно, но правда), я запустил их прямо из сети, используя адрес Sysinternals Live - live.sysinternals.com\tools\procmon.exe. С помощью функции Process Monitor записывающей активность я закрыл и снова открыл диалоговое окно выбора файлов в редакторе почты и начал искать CIMG - набор имен файлов, многие из которые отображались в диалоговом окне выбора файлов, но не в Windows Explorer. Первое совпадение произошло при перечислении операций с папками, содержащих такие имена файлов, которые показываются в самой правой колонке Details:

file2

 

Файлы находились в профиле пользователя в папке Appdata\Local\Microsoft\Windows\Temporary Internet Files\Virtualized\C\Users\Daryl\Desktop. Папка Virtualized является создается IE7 при запуске в защищенном режиме (Protected Mode, PMIE), который является стандартным в Windows Vista и Windows Server 2008. PMIE использует уровни целостности, представленные в Vista и Server 2008, для ограничения записей реестра и местоположений на диске, которые может модифицировать код, запущенный в IE. Как я уже описывал в более ранней статье, изолированная программная среда определяется местоположением, имеющим значение Low Integrity, уровнем на котором запускается PMIE, и определяет, какие объекты может изменять PMIE, что позволяет сохранять избранные ссылки и временные файлы как кэш IE и историю браузера. Однако, PMIE не может изменять другие папки в пользовательском профиле, такие как папки документов, ветки реестра и папки диска с указанием автоматически загружаемых программ для каждого пользователя, так как они имеют уровень целостности Medium. Это препятствует распространению так называемого drive-by-download вредоносного ПО, которое может заразить процесс IE благодаря постоянному присутствию в системе.


Чтобы сохранить обратную совместимость с унаследованным кодом, таким как элементы управления ActiveX и Browser Helper Objects, которые могут быть написаны с необходимостью создания файлов вне изолированной среды, PMIE создает компенсационный слой, который перехватывает операции с реестром и диском и перенаправляет операции, требующие доступ за пределы изолированной среды в виртуализированную папку.


Чтобы удостоверится в том, что произошло именно это, я изучил представленный выше стек трассировки виртуализированных операций, нажав правой кнопкой на строчке и выбрав элемент Stack. Выяснилось что библиотека Acredir.dll перехватывала операции и запускала функцию переадресации:

file3

Двойной щелчок на строке в трассировке стека открыл диалоговое окно свойств модуля, в котором было написано, что DLL является "Windows Compatibility DLL", таким образом, доказывая, что это часть реализации PMIE:

file4

Я уже был знаком с виртуализацией PMIE, но никогда не видел виртуализированные файлы на компьютере, поэтому для меня не было очевидного ответа, что стало причиной такого несоответствия. Process Monitor показал причину, поэтому все, что мне оставалось сделать - удалить виртуализированные файлы. Большинство пользователей не знают, что могут перемещать и удалять файлы из диалогового окна выбора файлов, поэтому я использовал возможность показать своей жене, что она может управлять виртуализированными файлами из диалогового окна редактора почты при выборе файлов, если она вдруг столкнется с данной проблемой в будущем. Мы удалили файлы, которые ей были не нужны, и переместили нужные файлы в ее папки библиотек фотографий.


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


Между прочим, скорее всего вы увидите файлы и папки, если загляните в виртуализированную папку PMIE в вашем профиле, так как даже самые рутинные операции в IE приводят к переадресации. Здесь вы можете увидеть файлы кэша эскизов, которые создает диалоговое окно оболочки для просмотра файлов в IE. Обычно оболочка хранит файлы кэша эскизов в вашем профиле, но PMIE не имеет туда доступа, поэтому все они виртуализируются.

 

file5

 

Оригинал записи

Posted by abeshkov | 0 Comments

Дело о прервавшемся телефонном звонке

У Дэвида Соломона (David Solomon), моего соавтора по книгам Windows Internals, недавно был очень важный разговор в VoIP-сети Skype, когда звук неожиданно исказился. Через секунду привычный рабочий стол сменил BSOD. После того, как он перезагрузил компьютер, он перезвонил, но через полчаса голос собеседника снова прервался на середине, а потом на экране возник очередной BSOD. Так как разговор все равно подходил к концу и причина падений была не ясна, Дэвид решил не перезванивать, считая, что формально разговор уже закончен, но зато решил разобраться в причинах сбоя. Он запустил Windbg из пакета Debugging Tools for Windows, в меню выбрал пункт Open Crash Dump и выбрал файл %Systemroot%\Memory.dmp.


До этого он настроил Windbg на использование публичного сервера символов Microsoft, введя для этого srv*c:\symbols*http://msdl.microsoft.com/download/symbols в диалоговом окне Windbg по настройке символов, поэтому Windbg знал, как интерпретировать dump-файл. Когда Windbg загружает файл дампа, то он автоматически инициирует эвристический механизм анализа, который и определяет драйвер или компонент системы, который, вероятнее всего, и виноват в сбое. Результат анализа указал на драйвер устройства NETw4v64.sys.

skype1

Когда в результатах вы щелкаете по ссылке !analyze -v, Windbg выводит данные, используемые во время анализа. Эвристический анализ не идеален, поэтому Дэвид всегда щелкает по этой ссылке, чтобы получить дополнительные данные, в особенности трассировку стека на момент сбоя и информацию о возможных участках данных, связанных со сбоем. В трассировке стека записан постоянный повторяющийся вызов функции процессора, который и привел к сбою ядра - KeBugCheckEx. В данном случае стек выглядел следующим образом:

skype2

Для сохранения хронологии вызова функций записи в стеке необходимо читать снизу вверх. Трассировка показывает, что какой-то код в NETw4v64 вызывает функцию NT-ядра KeAcquireSpinLockRaiseToDpc. Фрейм стека NETw4v64 не имеет текстового имени функции, которое должно быть у драйверов, не являющихся частью Windows, и, как следствие, не имеют символов на сервере символов Microsoft. Следующий, более высокоуровневый фрейм, показывает, что KeAcquireSpinLockRaiseToDpc вызывал KiPageFault, скорее всего, не напрямую, но это произошло в результате ссылки на адрес виртуальной памяти, которая на тот момент не была резидентной в физической памяти. Потом KiPageFault вызвал функцию KeBugCheckEx с кодом остановки А, который расширенный анализ описал как IRQL_NOT_LESS_OR_EQUAL:

skype3

Дэвид предположил, что NETw4v64 вызывал драйвер с помощью неправильного указателя, который вызывал неправильную ссылку на память. Этот конкретный сбой мог быть результатом случайного повреждения, вызванного сторонним драйвером, поэтому он открыл папку %Systemroot%\Minidump в поисках дампа первого сбоя системы. В Windows Vista, в которой работал Дэвид, система всегда записывает дамп памяти и ядра в файл, расположенный по адресу %Systemroot%\Memory.dmp, при этом перезаписывая предыдущий дамп, и сохраняет укороченную версию дампа, называемую минидамп, в папку %Systemroot%\Minidump. После этого Дэвид проделал те же шаги и со вторым дампом и механизм анализа сообщил о той же самой причине сбоя, указав на тот же самый поврежденный указатель значения памяти.


Без тщательного ручного анализа дампа вы не можете быть уверенными в том, что виноват эвристический указатель драйвера, но первое правило при расследовании сбоя состоит в том, чтобы проверить наличие последних версий драйверов. Иногда на Windows Update появляются опциональные обновления, которые не применяются к системе автоматически, поэтому Дейв зашел в папку %Systemroot%\System32\drivers, чтобы найти драйвер NETw4v64.sys и разобраться, какое устройство его использует. В диалоговом окне свойств файла было сказано, что файл имеет версию 11.5 и относится к Intel Wireless WiFi Link Driver.

skype4

Вооруженный знаниями о том, что это драйвер беспроводного адаптера Intel, Дейв зашел в диспетчер устройств, раскрыл ветку сетевых адаптеров и  нашел устройство с похожим именем:

skype5

Чтобы запустить мастер обновления, в контекстном меню он выбрал опцию обновления драйверов и запустил автоматический поиск на Windows Update. К сожалению, система отрапортовала, что в системе установлена новейшая версия драйвера.

skype6

Иногда на сайтах у OEM-производителей есть драйвера, которые они еще не опубликовали в Windows Update, поэтому Дейв зашел на сайт Dell, производителя его ноутбука, и проверил там. К сожалению, ситуация опять повторилась - там был такой же драйвер.

skype7

 

OEM-производители, в свою очередь, часто обращаются к производителям устройств за созданием устройства, соответствующего определенным требования по стоимости, питанию, возможностям или размеру. Вследствие этого производители оборудования не публикуют драйвера для каждого отдельного OEM-устройства, равно как и общие драйвера, которые могут и не использовать все функции конкретного OEM-устройства. Поэтому Дэвид зашел на сайт Intel. К его удивлению, там нашлась не только версия драйвера, которая безо всяких проблем установилась и заработала на его компьютере: выяснилось, что драйвер от Intel имел версию 12.1, то есть на целую версию выше, чем тот, который размещает на своем сайте Dell.

skype8

Intel предлагает для загрузки архив с драйверами объемом менее 7 МБ, что составляет 1/10 пакета от Dell, при этом в комплект входит дополнительное программное обеспечение для управления устройством.


Дейв не смог окончательно закрыть дело, так как у него не было уверенности, что именно драйвер от Intel был причиной сбоя, но после установки новой версии драйвера сбоев системы более не наблюдалось. Даже если основной причиной был не драйвер от Intel, Дейв все равно был доволен установкой новой версии драйвера, которая оказалась более производительной, надежной и более экономичной в плане потребления питания. Это дело является отличным уроком по анализу дампов и хорошим примером того, что даже на Windows Update и сайтах OEM-производителей могут быть не самые новые версии драйверов. Надеюсь, что Dell впредь будет использовать Windows Update, чтобы рассылать своим пользователям новейшие версии драйверов.

Оригинал записи

Posted by abeshkov | 1 Comments

Преодолевая ограничения Windows: виртуальная память

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


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


Адресное пространство процессов
У каждого процесса есть своя собственная виртуальная память, именуемая адресным пространством, в которой исполняется код этот процесса и его данные, на которые этот код ссылается и которыми управляет. 32-битные процессы используют 32-битные указатели на адреса в виртуальной памяти, которые создают абсолютный верхний предел в 4 ГБ (2 в 32-ой степени) на объем виртуальной памяти, которую 32-битный процесс может адресовать. Однако, чтобы операционная система могла обратиться к своему собственному коду и данным и к коду и данным, выполняющегося в настоящее время процесса, без необходимости изменять адресное пространство, она делает свою виртуальную память видимой из адресных пространств всех процессов. По умолчанию 32-битная версия Windows разделяет адресное пространство процесса поровну между системой и активным процессом, создавая границу в 2 Гб для каждого:

vm1

Приложения могли бы использовать для распределения виртуальной памяти Heap API, сборщик мусора .Net или Malloc-библиотеку C, но все они так или иначе опираются на VirtualAlloc API. Когда приложение исчерпывает свое адресное пространство, VirtualAlloc, а, следовательно, и диспетчеры памяти, построенные на его основе, возвращают ошибки (представленные адресом NULL). Утилита Testlimit, которую я написал для четвертого издания Windows Internals для того, чтобы продемонстрировать различные ограничения Windows, многократно вызывает VirtualAlloc до тех пор, пока не получит ошибку, вызванную указанием параметра -r. Таким образом, когда вы запускаете 32-битную версию Testlimit на 32-битной Windows, она займет все 2 Гб своего адресного пространства:

vm2

2010 Мб - это чуть меньше 2-х гигабайт, но наличие в памяти кодов и данных Testlimit, включая исполнительные и системные DLL, объясняют эту разницу. В графе Virtual Size утилиты Process Explorer вы можете увидеть общий объем адресного пространства программы:

vm3

Некоторые приложения, такие как SQL Server и Active Directory, управляют большими структурами данных, объем которых намного превышает доступное для них адресное пространство. Поэтому в Windows NT 4 SP3 ввели загрузочную опцию /3GB, позволяющую предоставить процессу 3 Гб из его четырех гигабайтного адресного пространства, уменьшая системное адресной пространство до 1 Гб, а в Windows XP и Windows Server 2003 встроили функцию /userva, которая перемещает границу разделения в пределах с 2 до 3 Гб:

vm4

Однако, чтобы использовать адресное пространство выше отметки 2 Гб, в исполняемом образе приложения обязательно должен содержаться набор флагов "large address space aware". Доступ к дополнительной виртуальной памяти является опциональным, потому что некоторые приложения рассчитаны на то, что им будет предоставлено не более 2 Гб адресного пространства. Так как старший разряд указателя, ссылающегося на адрес ниже отметки 2 Гб, всегда является нулем, они использовали бы его как флаг для их собственных данных, очищая его прежде, чем ссылаться на данные. Если бы такие приложения работали в 3-х гигабайтном адресном пространстве, они бы отсекли указатели, значения которых находятся выше 2 Гб, вызывая тем самым ошибки, в том числе и возможное нарушение целостности данных.


Все серверные продукты Microsoft и приложения Windows, интенсивно использующие память, имеют поддержку специального флага, позволяющего использовать адресное пространство выше отметки 2 ГБ; среди таких приложений Chkdsk.exe, Lsass.exe (которая являются главными сервисами Active Directory на контроллере домена), Smss.exe (менеджер сессий) и Esentutl.exe (инструмент восстановления базы данных Jet Active Directory). При помощи утилиты Dumpbin, входящей в состав Visual Studio, вы можете увидеть, у образов каких приложений есть этот флаг:

vm5

Testlimit также имеет этот флаг, так что если вы запустите его с параметром -r в 3-х гигабайтном пользовательском адресном пространстве, вы увидите что-то наподобие этого:

vm6

Поскольку адресное пространство в 64-битных Windows намного больше 4 Гб, такие версии Windows могут дать 32-битным процессам максимальные 4 Гб, которые они могут адресовать, и использовать оставшуюся виртуальную память для нужд операционной системы. Если вы запустите Testlimit на 64-битной Windows, то увидите, что она занимает все адресное пространство, к которому могут обратиться 32-разрядные приложения:

vm7

64-битные процессы используют 64-битные указатели, так что их теоретическое максимальное адресное пространство равно 16 экзабайтам (2 в 64-ой степени). Однако, Windows не делит адресное пространство равномерно между активными процессами и системой, а вместо этого определяет область в адресном пространстве для процессов и других системных ресурсов памяти, таких как системные записи таблицы страниц (PTE), файловые кэши, резидентный и нерезидентный (paged и non-paged) пулы.


Размеры адресного пространства процессов отличаются в IA64 и x64-версиях Windows, где он определяется так, чтобы соблюдался баланс между тем, сколько памяти требуется приложению, и издержками верхней памяти (страницы таблицы страниц и записи буфера трансляции адресов TLB), необходимых для поддержания адресного пространства. Для x64 это 8192 Гб (8 Тб), а для IA64 - 7168 Гб (7Тб) (разница в 1 Тб объясняется тем, что каталоги страниц верхнего уровня в IA64 резервируют слоты для распределений Wow64). И в IA64- и в x64-версиях Windows размер областей адресного пространства для различных ресурсов составляет 128 Гб (например, для нерезидентного пула отводится 128 Гб адресного пространства), за исключением кэша файла, которому выделяется 1 Тб. Поэтому адресное пространство 64-битного процесса выглядит примерно вот так:

 

 

 

 

 

vm8

На этом рисунке не соблюден масштаб, поскольку в ином случае даже 8 Тб, не говоря уже о 128 Гб, выглядели бы на нем тоненькой полоской. Я использовал этот рисунок, чтобы показать вам, что, как и в случае с нашей вселенной, в адресном пространстве 64-битного процесса есть много незанятного места.


Когда вы запустите 64-битную версию Testlimit (Testlimit64) на 64-битной Windows с параметром -r, вы увидите, что она занимает 8 Тб, которые являются той частью адресного пространства, которыми она может управлять:

vm9

vm10

Выделенная память
Параметр -r в утилите Testlimit резервирует виртуальную память, но не выделяет ее. Зарезервированная виртуальная память не может хранить данные или код, но приложения иногда используют резервирование для создания больших блоков виртуальной памяти, которую впоследствии они могут выделять, когда необходимо, чтобы выделенная память находилась в смежной с адресным пространством области. Когда процесс выделяет область в виртуальной памяти, операционная система гарантирует, что может предоставить для размещения всех данных процесса область или в физической памяти, или на диске. Это означает, что процесс может столкнуться с еще одним видом ограничений: ограничением на объем выделяемой памяти.


Из вышеизложенного следует, что граница у объема выделяемой памяти равна сумме физической памяти и размера файла подкачки. В действительности в определении границы учитывается не вся физическая память, потому как ее часть операционная система резервирует для своих нужд. Объем выделенной виртуальной памяти для всех активных процессов, называемый текущей выделенной памятью (current commit charge), не может превысить предела, установленного системой. Когда этот предел достигнут, службы, занимающиеся выделением виртуальной памяти, выдают ошибку. Это означает, что даже стандартный 32-битный процесс может столкнуться с ошибкой выделения виртуальной памяти еще до того, как он достигнет предела на объем виртуального адресного пространства в 2 Гб.


Текущий объем выделенной памяти и ее ограничение можно посмотреть в окне System Information утилиты Process Explorer в разделе Commit Charge и на графике Commit History:

 

 

vm11

Диспетчер задач в системах до Vista и Windows Server 2008 точно показывает эти параметры, но там текущий объем выделенной памяти на графике назван "PF Usage":

vm12

В Vista и Server 2008 диспетчер задач не показывает график текущей выделенной памяти, а отображает эти два значения в строке Page File (даже если вы отключите файл подкачки, эти значения будут ненулевыми):

vm13

Чтобы проверить значение границы выделенной памяти, вы можете запустить Testlimit с параметром -m, чтобы программа распределила выделенную память. 32-битная версия Testlimit может и не достигнуть предела своего адресного пространства до того, как достигнет предела на выделенную память; это зависит от объема физической памяти, размера файла подкачки и значения текущей выделенной памяти на момент запуска программы. Если вы используете 32-битную версию Windows и хотите увидеть, как поведет себя система при достижении предела на выделенную память, просто запустите несколько экземпляров Testlimit до тех пор, пока один из них не достигнет предела выделенной памяти до того, как исчерпает свое адресное пространство.


Здесь следует отметить, что по умолчанию файл подкачки настроен так, чтобы увеличиваться в размерах. Это означает, что предел для выделенной памяти также будет расти по мере приближения к нему значения выделенной памяти. И даже тогда, когда файл подкачки достигнет своего максимального размера, Windows может освободить еще немного памяти, которую она зарезервировала, аналогично тому, как некоторые приложения создают кэш данных. Testlimit знает об этом, и когда она достигает предела для выделенной памяти, приложение несколько секунд бездействует, а затем пытается получить еще немного памяти. Приложение будет повторять попытки до тех пор, пока вы его не отключите.


Если вы запустите 64-битную версию Testlimit, то она почти наверняка достигнет предела для выделенной памяти до того, как исчерпает свое адресное пространство, если, конечно, размеры файлов подкачки и физической памяти не дают в сумме более 8 Тб, которые, как описано ранее, являются пределом 64-битного адресного пространства, доступного приложению. Вот фрагмент результатов работы 64-битной версии Testlimit, запущенной на моей системе с 8Гб памяти (я указал размер на выделяемую память в 100 Мб, чтобы быстрее достигнуть предела):

vm14

А вот график для выделяемой памяти, на котором шаги соответствуют паузам в работе Testlimit, сделанным для того, чтобы файл подкачки смог увеличиться:

vm15

Когда у системы остается мало виртуальной памяти, приложения могут зависать и вы можете увидеть странные сообщения об ошибке, когда выполняете стандартные операции. Тем не менее, в большинстве случаев Windows выводит диалоговое окно, сообщающее о недостатке виртуальной памяти, наподобие того, которое система показала мне во время проведения теста:

vm16

После того, как вы закроете Testlimit, ограничение на выделенную память, скорее всего, вернется на прежний уровень, когда диспетчер памяти уменьшит размер файла подкачки. На следующем снимке экрана Process Explorer показывает, что предел для выделенной памяти находится ниже того пика, который был достигнут во время работы Testlimit:

 

 

 

 

 

vm17

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


Не вся виртуальная память, которой владеет процесс, имеет отношение к пределу выделенной памяти. Как вы уже знаете, примером здесь может служить зарезервированная виртуальная память. Виртуальная память, которая представляет файл на диске (такое представление носит название File Mapping View), также не участвует в расчете этого предела, за исключением случаев, когда приложение требует семантики copy-on-write, потому что Windows может стереть любые данные, связанные с образами в физической памяти, а после восстановить их из этого файла. Поэтому виртуальная память из адресного пространства Testlimit, в которую отображаются ее исполнительные и системные DLL, не учитывается при расчете предела выделенной памяти. Есть два типа виртуальной памяти процесса, которые учитываются при определении границы выделенной памяти: эти области называются "private" и "pagefile-backed".


Закрытая виртуальная память является тем видом виртуальной памяти, на основе которого строятся Garbage Collector Heap, Native Heap и Language Allocator. Она называется закрытой, потому что к ней не может быть открыт общий доступ для других процессов. По этой причине ее легко приписать к процессу, а Windows может отслеживать ее использование с помощью счетчика Private Bytes. Process Explorer отображает объем используемой закрытой памяти процесса в графе Private Bytes секции Virtual Memory на страницу Performance диалогового окна свойств процесса, а также отображает эти показатели в графическом виде на странице Performance Graph. Вот как выглядел Testlimit64 после достижения предела выделенной памяти:

vm18

vm19

Виртуальную память Pagefile-backed сложно отнести к конкретному процессу, потому что она может одновременно использоваться несколькими процессами. Фактически, нет никакого счетчика, привязанного к одному конкретному процессу, позволяющего посмотреть, сколько памяти этому процессу выделено или на какой объем этой памяти он ссылается. Когда вы запускаете утилиту Testlimit с параметром -s, она начинает занимать участки виртуальной памяти pagefile-backed до тех пор, пока не достигнет предела для выделенной памяти, но даже когда объем выделенной памяти превысит 29 Гб, статистика потребления виртуальной памяти для данного процесса не будет содержать ни одного указателя на то, что он один ответственен за это:

vm20

Именно по этой причине в программу Handle я добавил параметр -l. Процесс должен открыть объект в виртуальной памяти pagefile-backed, носящий название секции, для создания отображения виртуальной памяти pagefile-backed в его адресном пространстве. Так как Windows сохраняет существующую виртуальную память, даже если приложение закроет дескриптор к секции, из которой он был создан, большинство приложений сохранят этот дескриптор открытым. Параметр -l отображает размеры областей для секций pagefile-backed, которые открыты процессами. Вот часть результатов работы Handle для утилиты Testlimit, после того, как она была запущена с параметром -s:

vm21

Как видите, Testlimit занимает память pagefile-backed блоками по 1 Мб, и если просуммировать размер всех блоков, открытых этой программой, можно увидеть, что она является одним из процессов, занявших наибольший объем выделенной памяти.


Насколько большим следует сделать файл подкачки?
Возможно, наиболее частым вопросом, связанным с виртуальной памятью, является вопрос "насколько большим следует сделать файл подкачки?". Ни в сети, ни в информационных изданиях, освещающих вопросы Windows, нет конкретного ответа на этот вопрос, и даже Microsoft опубликовала на этот счет довольно запутанные рекомендации. Почти все советы основаны на умножении объема оперативной памяти на некоторое значение, например, на 1.2, 1.5 или 2. Теперь, когда вы понимаете, какую-роль играет файл подкачки в определении системного лимита на выделенную память и как процессы влияют на объем выделенной памяти, мы легко можете увидеть, насколько бесполезны такие формулы в действительности.


Так как предел для выделенной памяти устанавливается на основе того, сколько закрытой и pagefile-backed виртуальной памяти может быть одновременно выделено выполняющимся процессам, единственный способ правильно установить размер файла подкачки заключается в том, чтобы узнать, какой максимальный объем выделенной памяти может быть занят программами, которые вы часто запускаете одновременно. Если предел для выделенной памяти будет меньше этого значения, то ваши программы не смогут получить необходимую им виртуальную память и будут некорректно работать.
Так как же узнать, сколько выделенной памяти требуется вашей рабочей среде? На снимках экрана вы, возможно, заметили, что это число отслеживается Windows и Process Explorer показывает его: Peak Commit Charge. Чтобы установить оптимальный размер для вашего файла подкачки, вы должны запустить все приложения, с которыми вы работаете одновременно, загрузить типичный для вас объем данных и посмотреть пиковое значения выделенной памяти (или же посмотреть это значение по прошествии некоторого времени, когда, по вашему мнению, будет достигнута максимальная загруженность памяти). В качестве минимального размера файла подкачки установите это значение, отняв от него размер установленной на вашей системе оперативной памяти (если получиться отрицательное значения, выберите размер, позволяющий сохранить возможное количество отказов на минимальном уровне). Если вы хотите сохранить некоторый запас для потенциально больших расходов выделенной памяти, в качестве максимума установить это значение, умноженное на 2.


У вас может сложиться впечатление, что отсутствие файла подкачки может благотворно сказаться на производительности, однако в общем случае то, что у Windows в распоряжении будет файл подкачки, означает, что ОС сможет размещать некоторые записи (которые используются нечасто и не сохранены на диск) в файл подкачки, освобождая тем самым память для более полезных задач (процессы и кэши файлов). Так что даже если в некоторых случаях отсутствие файла подкачки может увеличить производительность, в общем случае его наличие означает, что в распоряжении системы будет больше доступной памяти (Windows в случае сбоя не сможет сделать дамп памяти, занятой под процессы ядра, если в ее распоряжении не будет достаточно большого файла подкачки).
Настройки файла подкачки находятся в окне Свойства системы, которое вы можете открыть, введя в окне Выполнить строчку "sysdm.cpl", после этого, зайдя на вкладку Дополнительно, нажать кнопку Параметры раздела Быстродействие, затем на вкладке Дополнительно нажать кнопку “Изменить”:

 

 

 

 

vm22

Там вы можете заметить, что по умолчанию Windows сама управляет размером файла подкачки. Когда это опция установлена в Windows XP и Server 2003, ОС создает один файл подкачки, минимальный размер которого равен 1,5 объема ОП системы; если объем оперативной памяти больше 1 Гб, то такой же размер устанавливается для файла подкачки; максимальный размер файла подкачки равен трем объема ОП. В Windows Vista и Server 2008 минимальное значения должно быть достаточно для того, чтобы в случае сбоя системы сделать дамп памяти, занятой под процессы ядра, и равно ОП+300 Мб или 1 Гб, в зависимости от того, какое значение окажется больше. Максимально значение - три объема оперативной памяти или 4 Гб, в зависимости от того, что окажется больше. Это объясняет тот факт, что на моей 64-битной системе с 8 Гб ОП пиковое значения выделенной памяти равно 32 Гб.


Другими ограничениями, связанными с виртуальной памятью Windows, являются максимальный размер и количество файлов подкачки. Для 32-битной Windows максимальный размер файла подкачки равен 16 Тб (4 Гб, если вы по какой-то причине работаете в режиме non-PAE), а 64-битная Windows может иметь файл подкачки размером до 16 Тб для x64 и 32 Тб в случае IA64. Для всех версий Windows есть возможность создавать до 16 файлов подкачки, каждый из которых должен располагаться на разных томах.

Оригинал записи

Posted by abeshkov | 1 Comments

Дело о мееееедленной системе

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


Первое, что я сделал - это запустил Process Explorer, чтобы понять, какой процесс нещадно потреблял все ресурсы процессора. Через несколько минут томительного ожидания Process Explorer запустился и показал, что не один, а даже несколько процессов и потребляли все мощности процессора, каждый по 50%: iexplore.exe и dllhost.exe. Iexplore, как вы, наверное, догадались, это Internet Explorer (IE). Но я предположил, что причиной проблемы, скорее всего, является не сам IE, а один из BHO-объектов (абб. от browser helper object), элемент управления ActiveX или какой-нибудь плагин, загруженный в IE. Dllhost.exe является корневым процессом для COM сервера DLL-библиотек, так что проблема явно была не в самом процессе, а в COM-сервере, загруженном в процесс. Оба варианта требовали дальнейших изысканий.
Начать я решил с IE. В попытке высвободить немного вычислительной мощи, в рамках которой я бы смог действовать, я приостановил процесс Dllhost, кликнув по нему правой кнопкой в Process Explorer и выбрав в контекстном меню опцию Suspend:

Это действие перевело статус процесса Dllhost в состояние сна и, как я и ожидал, высвободило порядка 50% процессорного времени. Это произошло потому, что компьютер построен на базе двухъядерного процессора, и для потребления всех 100% процессорных циклов процесс должен иметь два потока, чтобы каждый поток загружал по одному ядру. Большинство ошибок, грузящих процессор, с которыми я встречался в реальной жизни, были однопотоковыми.


Не процессы исполняют код - его исполняют потоки, поэтому мне надо было заглянуть внутрь процесса IE, чтобы увидеть какой поток или потоки запущены. Поэтому дважды щелкнув на процессе Iexplore.exe в Process Explorer, я переключился на вкладку Threads. Было запущено несколько потоков, но один доминировал в потреблении ресурсов процессора.

Из своего опыта я знаю, что Ieframe.dll является частью IE, но чтобы в этом убедиться, на закладке Threads я нажал кнопку Modules и перешел на вкладку Details.

Так как описание не помогло в определении предназначения потока, я решил обратиться к еще одной подсказке - функции запуска. Так как мой Process Explorer настроен на получение символов для образов Windows из сервера символов Microsoft, то Process Explorer сразу же показывал мне название функции, с которой начиналось исполнение потока. Иногда DLL или функции, с которой начинается поток, достаточно, чтобы понять назначение потока, ставшего причиной проблемы. В данном случае поток начинался с функции CTablWindow::_TabWindowThreadProc. Эта функция запускает основной поток вкладок, но причина, почему этот поток потреблял столько ресурсов, осталась загадкой. Нужно было копнуть еще глубже и проверить, куда именно исполняется поток.


Чтобы узнать, что именно делает поток, я два раза щелкнул на списке потоков, чтобы открыть диалоговое окно стека потока, которое показывает функции в стеке потока. По сути, стек - это история запуска функций, в которой каждая указанная функция вызвана функцией, находящейся выше по списку, а самая первая в списке функция, была выполена потоком как раз перед тем как Process Explorer подключился к стеку. Я пролистал список, чтобы найти строки, которые бы указывали на обращение к сторонним DLL или плагинам IE, так как вероятность того, что ошибка была именно в них намного больше, чем если бы она была в самом IE. Действительно, я нашел ссылки, указывающие на популярный элемент управления ActiveX - Adobe Flash:

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


Первое, что я делаю, когда подозреваю, что какое-либо ПО вызывает проблему, это проверяю сайт производителя, чтобы убедится, что у меня последняя версия ПО. Я открыл режим просмотра DLL в Process Explorer и посмотрел версию Flash.ocx, потом я перешел на сайт Adobe, посмотрел на последнюю версию Flash. Они совпадали.


Я был в тупике. Я не мог понять, где кроется ошибка - в самом Flash или, что более вероятно, в Flash-приложении. Также не было никакой уверенности в том, что проблема снова себя проявит. Я пытался определить, на каком сайте присутствует Flash-контент, закрывая вкладки одну за одной, но даже когда я закрыл их все, поток все равно работал.


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


Теперь я вернулся к проблеме Dllhost в надежде, что здесь мне удастся найти решение проблемы. В всплывающем окне Process Explorer показывает компонент или компоненты, загруженные в корневые процессы Svchost.exe (обслуживающий корневой процесс Windows), Rundll32 (корневой процесс аплетов панели управления), Taskeng.exe (корневой процесспланировщика заданий в Vista и Server 2008) и Dllhost.exe. Я навел мышку на Dllhost.exe, чтобы увидеть, какой COM-сервер запущен в рамках процесса.

Это был COM-сервер Thumbnail Cache, отвечающий за создание в Windows Explorer эскизов изображений и видео-файлов. Он является частью Windows, так что мне еще раз пришлось лезть внутрь процесса за дополнительными подробностями. Я снова запустил процесс Dllhost, который я приостановил ранее, и открыл страницу свойств потоков процесса.

В данном случае все мощности процессора потребляла функция ObjectThread из Quartz.dll. Я заглянул в ее свойства, и увидел, что это еще одна библиотека Windows, компонент DirectShow Runtime со стандартным именем функции:

Я снова дважды щелкнул на имени процесса, чтобы увидеть стек потока.

Первые несколько строчек содержали информацию о User32.dll и Ntdll.dll, основных системных библиотеках Windows, но в строчках 4-7 содержалась информация о стороннем компоненте Sonicmp4demux.ax (.ax - расширение, часто используемое фильтрами для DirectShow). Имена функций в этих библиотеках были те же самые, что не имело никакого смысла, так как сервер символов Microsoft хранит символы только для ПО, поставляемого с Windows. Еще несколько снимков состояния стека подтвердили, что это был именно тот код, который вызывал столь серьезное потребление ресурсов.


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

Ни в меню Start, ни в списке установленных приложений не было ничего похожего на Sonic. Я искал в Windows Live по запросу "Sonic" и узнал, что это часть программного пакета для работы с DC и DVD от Roxio. Я поискал в меню Start и, конечно же, нашел папку Roxio.

image

Я запустил приложение от Roxio, чтобы узнать номер версии, и обнаружил, что приложение Creator имеет встроенную возможность по проверке обновлений. Я запустил его, но обновлений не получил.

На всякий случай я зашел на сайт Roxio и оказалось, что таки есть новая версия, которую встроенный загрузчик не предлагал просто потому, что обновление, согласно описанию, не предлагало ничего нового.

image

Я все равно его загрузил (все 640 Мб!) и ждал около 15 минут, пока пакет установится. Потом я проверил информацию о версии Sonicmp4demux.ax, но номер версии - 1.4.402.60802 - был идентичен тому, который я видел в режиме просмотра библиотек, а сам файл был двухлетней давности.

Я мог бы удалить программный пакет и проблема более никогда бы не появилась, но мне не хотелось расставаться с возможностью создавать DVD с помощью Roxio. Для меня не являлось трагедией, если я больше не буду видеть специальные значки файлов форматов образов, связанных с Roxio, я даже не был уверен, что видел когда-либо таковой в Windows Explorer, поэтому я решил выключить только демультиплексор от Sonic. Я мог провести поиск в реестре по имени библиотеки, где она, конечно же, была зарегистрирована, но это грубый подход, и в случае существования непрямых или дублирующихся ссылок я мог легко дойти до того, что перестало бы работать не только создание эскизов изображений, но повредилось бы что-то более серьезное.


Process Monitor - лучше всего подходит для подобной работы. Так как я не знал, когда именно проблема появится снова, на ее повторение могли уйти дни, я не хотел просто запустить программу и отдать ей на съедение всю виртуальную память, так что я ограничил глубину хранения истории в Process Monitor 1 миллионом событий.

image

Также я включил фильтр на поиск совпадений с адресом C:\Windows\System32\Dllhost.exe, свернул программу и пустил жену за компьютер.


На следующий день, когда я вернулся с работы и сел за компьютер, я увидел, что процесс Dllhost.exe снова потребляет около 50% времени процессора. Я предположил, что так как система двухъядерная, то эта проблема появлялась регулярно, однако, моя жена этого не замечала, так как оставшихся ресурсов было достаточно, для нормальной работы (еще одна хорошая причина покупать многоядерные процессоры!). В Process Monitor за это время было записано около 114000 операций с Dllhost, что было явно слишком много, чтобы изучить их все индивидуально. Я запустил поиск sonicmp4 и ближе к концу трассировки нашел ссылку на запрос к реестру.

Система запрашивала зарегистрированый COM-объект мультиплексора. Так как COM-объект является сторонней библиотекой, то я был уверен, что COM Class ID (CLSID) не жестко прописан в Windows, так что я вернулся к началу трассировки и начал искать значение A7DD215 (первые несколько знаков данного CLSID). Поиск нашел совпадение на несколько тысяч операций раньше.

CLSID содержался в имени ключа реестра в еще одном регистраторе COM-объекта. Я провел поиск в Windows Live родительского CLSID и обнаружил эту статью в базе знаний Microsoft, в которой объяснено, в каком ключе реестра зарегистрированы фильтры DirectShow. Я взглянул на стек в поисках определенного запроса, чтобы убедится в том, что Dllhost читает данные именно оттуда.

Теперь я был уверен, что могу просто переименовать ключ регистрации фильтра Sonic, чтобы предотвратить его использование. Я никогда не удаляю ключи реестра, когда провожу такого рода диагностику, просто на случай, если изменение заблокирует важную функциональность или каким-то образом нанесет вред системе. Из трассировок я понял, что генератор кэша эскизов нашел AVI файл, который вынудил генератор кэша загрузить демультиплексор от Sonic, этот формат Windows явно может обработать и сама, так что я был уверен, что все продолжит работать нормально. После завершения процесса Dllhost и внесения изменений, я открыл ту же папку, удалил эскизы и убедился, что насколько я могу судить,  уменьшения функциональности не произошло. После чего я успешно воспользовался Roxio для записи DVD с множеством AVI-файлов. Дело было закрыто.


Системой моей жены снова можно было пользоваться и хотя я не смог раскрыть причин столь серьезной загрузки процессора Flash-плагином, я, по крайней мере, знал причину, поэтому мог следить за обновлениями. Что более важно, решив часть дела по Dllhost, даже если Flash опять начнет сходить с ума, я сделал систему снова годной к использованию. Теперь моя жена более не будет сталкиваться с такими инцидентами. В очередной раз спасибо Process Explorer и Process Monitor.

Оригинал записи

Posted by abeshkov | 0 Comments

Преодолевая ограничения Windows: физическая память

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


Физическая память
Одним из основных ресурсов любого компьютера является физическая память. Диспетчер памяти Windows наполняет память кодом и данными активных процессов, драйверов устройств и самой операционной системы. Так как в большинстве систем объем кода и данных, к которым производится обращение, превышает емкость физической памяти, то она демонстрирует, какой код и какие данные оказываются задействованы в тот или иной момент. Объем памяти влияет на производительность – когда данные или код, нужный процессу или операционной системе, отсутствует в памяти, диспетчер памяти вынужден подгружать его с диска.


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


Ограничения памяти в ОС Windows Server
Особенности поддержки физической памяти в ОС Windows продиктованы ограничениями оборудования, условиями лицензирования, характеристиками структур данных операционной системы и вопросами совместимости драйверов. На странице "Ограничения памяти в различных выпусках ОС Windows" (на английском языке) веб-узла MSDN изложены ограничения памяти, характерные для различных версий Windows и номеров SKU в рамках каждой версии.


Как видите, во всех серверных версиях ОС Windows разным номерам SKU соответствуют разные формы поддержки физической памяти, обусловленные условиями лицензионных соглашений. К примеру, 32-разрядная версия ОС Windows Server 2008 Standard поддерживает лишь 4 ГБ физической памяти, в то время как 32-разрядная версия Windows Server 2008 Datacenter – 64 ГБ. С другой стороны, 64-разрядная версия ОС Windows Server 2008 Standard поддерживает всего 32 ГБ физической памяти, а 64-разрядная версия Windows Server 2008 Datacenter – целых 2 ТБ. Систем с физической памятью объемом 2 ТБ не так уж много – участники рабочей группы по вопросам производительности ОС Windows Server знают пару таких, одна из которых в какой-то момент была собрана в их собственной лаборатории. Вот как выглядит диспетчер задач в такой системе.

clip_image002

Максимальный для 32-разрядных систем объем памяти – 128 ГБ – поддерживается версией Windows Server 2003 Datacenter Edition. Такое ограничение связано с тем, что в более мощных системах структуры, применяемые диспетчером памяти для отслеживания физической памяти, потребляли бы слишком большую часть пространства виртуальных адресов. Диспетчер памяти отслеживает страницы памяти при помощи массива, называемого базой данных PFN, и в целях оптимизации производительности отображает все содержимое этой базы в виртуальную память. Так как каждая страница памяти представлена структурой данных объемом 28 байт, в системе с физической памятью емкостью 128 ГБ для размещения базы данных PFN потребуется 930 МБ. В 32-разрядных ОС Windows предусмотрено пространство виртуальных адресов объемом 4 ГБ, зависящее от оборудования и по умолчанию распределяемое между текущим процессом пользовательского режима (например, блокнотом) и системой. В таких условиях база данных PFN объемом 980 МБ занимает почти половину из доступных 2 ГБ системной части пространства виртуальных адресов, а значит, на отображение ядра, драйверов устройств, системного кэша и других структур данных системы остается всего 1 ГБ (см. иллюстрацию).

clip_image002[4]

По той же причине в таблице ограничений объема памяти указаны пониженные лимиты для SKU при загрузке в режиме настройки систем с объемом памяти 4 ГБ (иначе называемом 4GT и включаемом параметрами загрузки /3GB или /USERVA файла Boot.ini и параметром /Set IncreaseUserVa программы Bcdedit). Дело в том, что для этого режима характерна такая схема разделения физической памяти, при которой процессам пользовательского режима достается 3 ГБ, а системе – всего 1 ГБ. В целях повышения производительности в ОС Windows Server 2008 для системных нужд резервируется более значимая доля адресного пространства. Для этого максимальный объем физической памяти, поддерживаемый в 32-разрядных версиях ОС, сокращается до 64 ГБ.


Диспетчер памяти мог бы высвободить память путем выборочного отображения фрагментов базы данных PFN в системные адреса по мере необходимости, однако этот вариант слишком сложен и имеет потенциал снижения производительности, связанного с дополнительными операциями отображения и отмены отображения. Лишь недавно стали появляться системы настолько производительные, чтобы такой вариант можно было рассматривать как реалистичный. Впрочем, так как размер системной части адресного пространства не является ограничением для отображения всей базы данных PFN в 64-разрядных версиях ОС Windows, поддержка большего объема памяти реализована именно в них.


Версия ОС Windows Server 2008 Datacenter поддерживает до 2 ТБ физической памяти. Такое ограничение не связано ни с особенностями реализации, ни с возможностями оборудования – все дело в том, что корпорация Майкрософт не объявляет о поддержке конфигураций, которые мы не в состоянии протестировать. На момент выпуска ОС Windows Server 2008 «рекорд» по объему памяти находился на отметке 2 ТБ – на этом и остановились.

Ограничения памяти в клиентских версиях ОС Windows
64-разрядные клиентские версии ОС Windows поддерживают разные объемы памяти – от 512 МБ в Windows XP Starter до 128 ГБ в Vista Ultimate. В то же время, все 32-разрядные клиентские версии ОС Windows, в том числе Windows Vista, Windows XP и Windows 2000 Professional, поддерживают физическую память в объеме до 4 ГБ. 4 ГБ – это максимальный физический адрес, доступный в стандартном режиме управления памятью x86. Некоторое время назад поддержка памяти в объеме свыше 4 ГБ была бессмысленна – системы с таким объемом памяти, даже серверные, встречались чрезвычайно редко.


К моменту разработки пакета обновления 2 (SP2) для ОС Windows XP появление клиентских систем с объемом памяти свыше 4 ГБ уже прогнозировалось, что заставило разработчиков приступить к интенсивному тестированию Windows XP на подобных системах. Кроме того, в пакете обновления 2 (SP2) для ОС Windows XP была реализована поддержка расширений физических адресов (PAE) по умолчанию для устройств, поддерживающих технологию No Execute, что, во-первых, необходимо для предотвращения исполнения данных (DEP), а во-вторых, обеспечивает возможность поддержки памяти в объеме более 4 ГБ.


В ходе тестирования выяснилось, что многие системы аварийно завершают работу, зависают и отказываются загружаться. Происходит это из-за того, что некоторые драйверы устройств, в особенности аудио- и видеоустройств, которые, в основном, встречаются в клиентских системах, а не в серверах, запрограммированы на работу с физическими адресами в пределах 4 ГБ. Эти драйверы, оказываются, обрубают адреса свыше 4 ГБ, что приводит к повреждению содержимого памяти со всеми вытекающими последствиями. В серверных же системах, которые, как правило, оснащаются менее специфичными устройствами с относительно простыми и надежными драйверами, подобные проблемы обнаружены не были. Выявленные недостатки экосистемы драйверов заставили применительно к клиентским версиям ОС отказаться от работы с памятью в объеме свыше 4 ГБ, несмотря на то, что теоретически её адресация возможна.


Фактические ограничения памяти в 32-разрядных клиентских системах
Согласно официальным условиям лицензии, в 32-разрядных клиентских версиях ОС допускается установка памяти в объеме до 4 ГБ. Фактически же лимит поддержки объема памяти ниже – кроме того, он зависит от набора микросхем и характеристик подключенных устройств. Дело в том, что в таблицу физических адресов включается не только оперативная память, но и память устройств. При этом для совместимости с 32-разрядными операционными системами, которые не способны обрабатывать адреса свыше 4 ГБ, в системах x86 и x64 память устройств отображается ниже границы адресации 4 ГБ. Предположим, если в системе установлено 4 ГБ оперативной памяти, а окна в память сетевых адаптеров, аудио- и видеоустройств в сумме составляют 500 МБ, то 500 МБ из 4 ГБ оперативной памяти окажутся за границей адресации (см. рисунок).

clip_image002[8]

Следовательно, оснащение 32-разрядной системы с клиентской версией ОС Windows памятью объемом 3 ГБ и выше, вполне возможно, не принесет желаемого эффекта. В ОС Windows 2000, Windows XP и Windows Vista RTM с объемом доступной памяти можно ознакомиться в диалоговом окне System Properties (Свойства системы), на странице Performance (Быстродействие) диспетчера задач. В ОС Windows XP и Windows Vista (в том числе с пакетом обновления 1 (SP1)) эти сведения можно также получить с помощью служебных программ Msinfo32 и Winver. С выходом пакета обновления 1 (SP1) для ОС Windows Vista некоторые из этих инструментов стали указывать объем установленной, а не доступной, памяти, о чем сказано в специальной статье базы знаний Майкрософт.


Как свидетельствует утилита Msinfo32, при загрузке моего ноутбука под управлением 32-разрядной версии Vista доступно 3,5 ГБ памяти из четырех установленных.

clip_image002[10]

Схему распределения физической памяти можно узнать с помощью служебной программы Meminfo, написанной Алексом Ионеску (Alex Ionescu – он, кстати сказать, принимает участие в подготовке пятого издания нашей с Дэвидом Соломоном (David Solomon) книги «Внутреннее устройство Windows»). Вот как выглядят выходные данные программы Meminfo, запущенной с параметром –r, который позволяет вывести на консоль диапазоны физической памяти.

clip_image002[12]

Обратите внимание на два разрыва между страницами: от 9F0000 до 100000 и от DFE6D000 до FFFFFFFF (4 ГБ). Характерно, что при загрузке того же компьютера с 64-разрядной версией Vista все 4 ГБ памяти отмечаются как доступные, а 500 МБ ОЗУ, оставшиеся выше отметки 4 ГБ, задействуются следующим образом.

clip_image002[14]

Так почему же эти разрывы возникают ниже границы 4 ГБ? Ответить на этот вопрос нам поможет диспетчер устройств. Запустите оснастку "devmgmt.msc", выберите в меню View (Вид) команду Resources by Connection (Ресурсы по подключению) и раскройте узел Memory (Память). На моем ноутбуке основным потребителем отображаемой памяти устройств, что не удивительно, является видеоадаптер, на долю которого приходится 256 МБ в диапазоне E0000000-EFFFFFFF:

clip_image002[16]

Оставшийся объем распределяется между другими устройствами. Кроме того, согласно консервативной оценке микропрограммы в период загрузки, шина PCI резервирует для устройств дополнительные диапазоны.


Потребление адресов памяти ниже 4 ГБ особенно заметно в мощных игровых системах с высокопроизводительными видеоадаптерами. Я как-то купил в магазине, специализирующемся на игровых компьютерах, систему с 4 ГБ ОЗУ и двумя видеоадаптерами по 1 ГБ каждый. Я не стал специально указывать свои предпочтения по части ОС, предполагая, что установлена 64-разрядная версия Vista. Вопреки моим ожиданиям, выяснилось, что они установили 32-разрядную версию, а значит, операционной системе доступно лишь 2,2 ГБ из установленной памяти. После установки 64-разрядной версии, по данным программы Meminfo, в диапазоне памяти между 8FEF0000 и FFFFFFFF образовался громадный разрыв.

clip_image002[18]

Диспетчер устройств сообщает о том, что 512 МБ в этом разрыве, составляющем в общей сложности свыше 2 ГБ, отводится видеоадаптерам (по 256 МБ каждому). Кроме того, похоже, микропрограмма зарезервировала дополнительный объем памяти – либо для динамического отображения, либо в силу консервативности оценки.

clip_image002[20]

Даже если система оснащена всего 2 ГБ физической памяти, может случиться так, что часть её окажется недоступной под управлением 32-разрядной версии Windows. Причиной тому – наборы микросхем, практикующие агрессивное резервирование областей памяти для устройств. На нашем общем семейном компьютере, купленном несколько месяцев назад у крупного изготовителя оборудования, доступно 1,97 ГБ из установленных 2 ГБ физической памяти.

clip_image002[22]

Диапазон физических адресов от 7E700000 до FFFFFFFF зарезервирован шиной PCI и устройствами. Таким образом, даже теоретически пространство физических адресов не может превышать 7E700000 байт (1,976 ГБ), но поскольку часть этого диапазона резервируется для памяти устройств, Windows сообщает о том, что общий объем памяти составляет 1,97 ГБ.

clip_image002[24]

Так как теперь для получения сертификата о подписывании драйверов изготовители оборудования должны предоставлять в лаборатории WHQL драйверы как для 32-разрядных, так и для 64-разрядных версий Windows, большинство современных драйверов вполне справляются с физическим адресами свыше 4 ГБ. 32-разрядные версии Windows в силу наличия риска, который очень трудно оценить, будут по-прежнему игнорировать память выше границы 4 ГБ. При этом изготовители оборудования в тех случаях, когда этому ничто не препятствуют, переходят (или, по крайней мере, должны переходить) на 64-разрядные версии.
Вывод прост: потребление памяти в полном объеме, каким бы существенным он ни был (конечно, в рамках ограничений версии), возможно только в 64-разрядных версиях Windows. При покупке специализированного игрового компьютера обязательно попросите изготовителя оборудования сразу установить 64-разрядную версию операционной системы.


Когда памяти достаточно?
Вне зависимости от объема установленной в системе памяти возникает вопрос: достаточен ли этот объем? К сожалению, определенного ответа на него нет. Делать какие-то выводы следует на основе регулярного наблюдения за объемом «доступной» памяти системы, особенно если выполнение задач, ставящихся перед компьютером, требует интенсивного потребления памяти. В терминах Windows доступной памятью называется физическая память, не закрепленная за процессом, ядром или драйвером устройства. Очевидно, при необходимости доступная память может быть выделена процессу или системе. Естественно, диспетчер памяти пытается использовать доступную память как можно эффективнее – он организует в ней файловый кэш (список ожидания) и список обнуленных страниц памяти. Кроме того, появившаяся в Windows Vista функция Superfetch проводит упреждающую выборку в список ожидания и приоритезацию данных и кода, отдавая предпочтение тем данным и коду, которые с наибольшей вероятностью будут востребованы в ближайшем будущем.


Дефицит доступной памяти свидетельствует о том, что к физической памяти активно обращаются процессы или система. Если же объем доступной памяти оказывается близким к нулю в течение длительного времени, значит, имеет смысл установить дополнительную память. Существует несколько способов мониторинга доступной памяти. В ОС Windows Vista опосредованно отслеживать объем доступной памяти помогает индикатор Physical Memory Usage History (Хронология использования физической памяти) диспетчера задач. Его значение должно быть постоянно приближено к 100%. Вот как выглядит диспетчер задач в моей настольной системе с объемом памяти 8 ГБ (кстати, не много ли у меня памяти?!).

clip_image002[26]

Во всех версиях ОС Windows график доступной памяти можно вывести при помощи системного монитора. Для этого нужно активировать счетчик Available Bytes (Доступно байт) из группы счетчиков Memory performance (Производительность памяти).

clip_image002[28]

С текущей величиной доступной памяти можно ознакомиться в диалоговом окне System Information (System Information) программы Process Explorer или (в предшествующих Vista версиях ОС Windows) на странице Performance (Быстродействие) диспетчера задач.


Как преодолеть ограничения
Из трех основных ресурсов – процессора, памяти и дисковой подсистемы – характеристики памяти, как правило, оказывают наибольшее влияние на общую производительность системы. Чем памяти больше, тем лучше. Быть уверенными в том, что весь потенциал установленной памяти реализован, вам помогут 64-разрядные версии ОС Windows. Они, между прочим, предоставляют ряд других преимуществ по части производительности, о которых я расскажу в одном из предстоящих выпусков серии «Преодолевая ограничения Windows», посвященном виртуальной памяти и её ограничениям.

Оригинал записи

Posted by abeshkov | 1 Comments

Дело о случайных сбоях Internet Explorer и Windows Media Player

Когда я впервые столкнулся со сбоями Internet Explorer (IE) на моей домашней 64-битной игровой системе, то изначально списал всю вину на повреждение памяти стороннего плагина. Я продолжил свою работу, но через несколько дней я снова столкнулся со сбоем IE, вслед за котором сбои стали случаться и при каждом третьем или четвертом запуске Windows Media Player (WMP).

 

randcrash0

Сбои в разных приложениях явно указывали на более фундаментальную проблему. Я разгонял свой процессор и поэтому грешным делом решил, что причиной сбоев является перегрев процессора, поэтому я с неохотой вернулся к стандартным настройкам множителя частоты процессора. Однако, к моему удивлению, сбои продолжались. Следующей моей теорией было то, что у меня проблемы с ОЗУ, но Windows Vista Memory Diagnostic не смогла найти каких-либо проблем.


После того, как стало понятным, что аппаратная составляющая не виновата, следующим моим шагом было изучение дампов на предмет наличия возможных зацепок. Но сначала мне надо было найти дамп сбоя. Процесс Application Error Reporting в Windows XP всегда создает дамп-файл перед тем, как открыть диалоговое окно о сбое программы, и вы всегда можете найти местоположение дампа, нажав на ссылке просмотра подробностей, а потом на ссылке по просмотру технических деталей отчета.

randcrash1

Соответствующий диалог в Windows Vista не предоставляет возможности просмотра технических подробностей, а также не создает файлы дампов, если серверы Windows Error Reporting (WER) его не запрашивают - это происходит только при получении информации о серьезном количестве таких сбоев. К счастью, WerFault, процесс, который представляет собой диалог о сбое программы, хранит информацию об сбойном процессе до тех пор, пока вы не нажмете кнопку Close Program, что дает возможность подключиться к процессу с помощью отладчика и изучить процесс. В Process Explorer вы можете увидеть, как WerFault обрабатывает аварийно завершившийся процесс Windows Media Player:

randcrash3

В следующий раз, когда я столкнулся со сбоем, я запустил WinDbg, отладчик Windows из пакета Debugging Tools for Windows, который доступен для бесплатной загрузки с сайта Microsoft. После того, как я убедился, что в диалоговом окне Symbol File Path выставлены настройки на подключение к публичному серверу символов Microsoft (то есть srv*c:\symbols*http://msdl.microsoft.com/download/symbols), я зашел в меню File и выбрал пункт Attach to a Process...

randcrash12

В следующий раз, когда я столкнулся со сбоем, я запустил WinDbg, отладчик Windows из пакета Debugging Tools for Windows, который доступен для бесплатной загрузки с сайта Microsoft. После того, как я убедился, что в диалоговом окне Symbol File Path выставлены настройки на подключение к публичному серверу символов Microsoft (то есть srv*c:\symbols*http://msdl.microsoft.com/download/symbols), я зашел в меню File и выбрал пункт Attach to a Process...

randcrash3

Данное действие открывает диалоговое окно WinDbg по выбору процесса, к которому необходимо подключится. Я пролистал весь список, чтобы найти сбойный процесс. Когда я выбрал нужный процесс, WinDbg открыл его и отобразил его точно также, как при загрузке файла дампа, за исключением того, что в данном случае вы не можете инициировать команду отладчика !analyze, которая запускает эвристический анализ для выяснения причины сбоя. При подключении отладчика анализ покажет то, что вы уже знаете: вы подключены с помощью отладчика.

randcrash4

Поиск потенциальных причин сбоя при подключении с помощью отладчика требует просмотра стека каждого потока в процессе, поэтому в меню View я открыл окна Processes and Threads и Call Stack.

randcrash6

Я начал изучать потоки с выбора первого элемента в окне потоков.

randcrash7

Обычно в такие моменты командное окно WinDbg становится серым и показывает окно с сообщением о том, что программа занята, так как WinDbg получает символы с публичного сервера, после чего в стеке вызовов потока появляется структура функций потока на момент сбоя. В порядке прямой последовательности я изучал каждый поток, передвигаясь между ними с помощью стрелки вниз и кнопки enter, охотясь за стеком, в котором были бы функции со словами exception или fault. Ближе к концу списка я столкнулся с этим:

randcrash8

Я заметил, что верхняя часть списка полна функций с суффиксом Exception. Просмотрев нижнюю часть списка (верхнюю часть стека), я заметил, что функция в Nvappfilter вызвала функцию HeapFree в Kernel32.dll, что и привело к аварийному завершению работы. Исключение в незанятых подпрограммах динамически распределяемой памяти значит, что или вызывающая функция обратилась к неправильному адресу памяти, или память уже была повреждена, когда функция начала исполнятся. Если бы вызывающей библиотекой была Windows DLL, то я об этом я бы узнал чуть позже, но в данном случае виновата была точно стороння библиотека: об этом говорил тот факт, что WinDbg не смог найти информацию для данного символа и, как следствие, не знал имени функций данной библиотеки. Я подтвердил свое предположение, запустив команду lm (list module), чтобы просмотреть информацию о версии.

randcrash9

Теперь основным подозреваемым стал Nvappfilter, но у меня не было доказательств того, что именно данная библиотека виновата в сбоях. Я продолжил пользоваться системой и проделал те же шаги во время следующих нескольких сбоев. Вне зависимости от того, какое приложение завершало свою работу с ошибкой, стек сбоя всегда был одним и тем же - Nvappfilter вызывал функцию HeapFree. Это все еще не решающее доказательство, но отдельные доказательства были уже налицо.


На данном этапе я решил проверить обновления Nvappfilter, но не знал точно, с каким именно приложением ассоциирована данная библиотека. Я ввел данное имя в поисковик и узнал, что это функция пакета nVidia FirstPacket, которая дает приоритет игровому трафику и входит в состав программного обеспечения для материнских плат nForce.

 

randcrash10

Я зашел на сайт nVidia и загрузил последнюю версию nForce, но пакет не смог обновить Nvappfilter.dll, поэтому сбои продолжались.


В панели управления nVidia я не смог найти способ предотвращающий загрузку Nvappfilter, поэтому мне надо было самому отключить данную функцию. Я не стал использовать функцию FirstPacket, поскольку раньше я и не знал, как ей пользоваться, но для начала мне было нужно понять, как данной библиотеке удалось настроить Windows на свою загрузку. Для этого я запустил программу Autoruns и в меню Winsock Layered Service Provider (LSP) я нашел ссылки на 32- и 64-битные версии Nvappfilter.

 

randcrash11

Я удалил все упоминания о Nvappfilter и с тех пор не было никаких сбоев. Пока я писал данную статью, я снова проверил обновления nForce на предмет обновленной версии Nvappfilter. В новых версии Nvappfilter или любой другой Winsock LSP отсутствует, поэтому предположение о том, что Nvappfilter был виноват в падениях, оказалось верным.


В ходе расследования этого дела я также был вынужден прибегнуть к функциональности локальных дампов в Vista SP1. Поэтому в будущем я буду автоматически получать файлы дампов для расследования при сбое какого-либо приложения. Если вы создадите ключ под названием HKLM\Software\Microsoft\Windows\Windows Error Reporting\LocalDumps, то WerFault всегда будет сохранять дамп. По умолчанию они сохраняются в папку %LOCALAPPDATA%\Crashdumps, но в реестре вы можете изменить данное значение, а также количество сохраняемых WerFault-дампов.

 

Оригинал записи

Posted by abeshkov | 0 Comments

Дело о случайных сбоях Internet Explorer и Windows Media Player

Когда я впервые столкнулся со сбоями Internet Explorer (IE) на моей домашней 64-битной игровой системе, то изначально списал всю вину на повреждение памяти стороннего плагина. Я продолжил свою работу, но через несколько дней я снова столкнулся со сбоем IE, вслед за котором сбои стали случаться и при каждом третьем или четвертом запуске Windows Media Player (WMP).

 

randcrash0

Сбои в разных приложениях явно указывали на более фундаментальную проблему. Я разгонял свой процессор и поэтому грешным делом решил, что причиной сбоев является перегрев процессора, поэтому я с неохотой вернулся к стандартным настройкам множителя частоты процессора. Однако, к моему удивлению, сбои продолжались. Следующей моей теорией было то, что у меня проблемы с ОЗУ, но Windows Vista Memory Diagnostic не смогла найти каких-либо проблем.


После того, как стало понятным, что аппаратная составляющая не виновата, следующим моим шагом было изучение дампов на предмет наличия возможных зацепок. Но сначала мне надо было найти дамп сбоя. Процесс Application Error Reporting в Windows XP всегда создает дамп-файл перед тем, как открыть диалоговое окно о сбое программы, и вы всегда можете найти местоположение дампа, нажав на ссылке просмотра подробностей, а потом на ссылке по просмотру технических деталей отчета.

randcrash1

Соответствующий диалог в Windows Vista не предоставляет возможности просмотра технических подробностей, а также не создает файлы дампов, если серверы Windows Error Reporting (WER) его не запрашивают - это происходит только при получении информации о серьезном количестве таких сбоев. К счастью, WerFault, процесс, который представляет собой диалог о сбое программы, хранит информацию об сбойном процессе до тех пор, пока вы не нажмете кнопку Close Program, что дает возможность подключиться к процессу с помощью отладчика и изучить процесс. В Process Explorer вы можете увидеть, как WerFault обрабатывает аварийно завершившийся процесс Windows Media Player:

randcrash12

В следующий раз, когда я столкнулся со сбоем, я запустил WinDbg, отладчик Windows из пакета Debugging Tools for Windows, который доступен для бесплатной загрузки с сайта Microsoft. После того, как я убедился, что в диалоговом окне Symbol File Path выставлены настройки на подключение к публичному серверу символов Microsoft (то есть srv*c:\symbols*http://msdl.microsoft.com/download/symbols), я зашел в меню File и выбрал пункт Attach to a Process...

 

randcrash3

Данное действие открывает диалоговое окно WinDbg по выбору процесса, к которому необходимо подключится. Я пролистал весь список, чтобы найти сбойный процесс. Когда я выбрал нужный процесс, WinDbg открыл его и отобразил его точно также, как при загрузке файла дампа, за исключением того, что в данном случае вы не можете инициировать команду отладчика !analyze, которая запускает эвристический анализ для выяснения причины сбоя. При подключении отладчика анализ покажет то, что вы уже знаете: вы подключены с помощью отладчика.

randcrash4

Поиск потенциальных причин сбоя при подключении с помощью отладчика требует просмотра стека каждого потока в процессе, поэтому в меню View я открыл окна Processes and Threads и Call Stack.

randcrash6

Я начал изучать потоки с выбора первого элемента в окне потоков.

randcrash7

Обычно в такие моменты командное окно WinDbg становится серым и показывает окно с сообщением о том, что программа занята, так как WinDbg получает символы с публичного сервера, после чего в стеке вызовов потока появляется структура функций потока на момент сбоя. В порядке прямой последовательности я изучал каждый поток, передвигаясь между ними с помощью стрелки вниз и кнопки enter, охотясь за стеком, в котором были бы функции со словами exception или fault. Ближе к концу списка я столкнулся с этим:

randcrash8

Я заметил, что верхняя часть списка полна функций с суффиксом Exception. Просмотрев нижнюю часть списка (верхнюю часть стека), я заметил, что функция в Nvappfilter вызвала функцию HeapFree в Kernel32.dll, что и привело к аварийному завершению работы. Исключение в незанятых подпрограммах динамически распределяемой памяти значит, что или вызывающая функция обратилась к неправильному адресу памяти, или память уже была повреждена, когда функция начала исполнятся. Если бы вызывающей библиотекой была Windows DLL, то я об этом я бы узнал чуть позже, но в данном случае виновата была точно стороння библиотека: об этом говорил тот факт, что WinDbg не смог найти информацию для данного символа и, как следствие, не знал имени функций данной библиотеки. Я подтвердил свое предположение, запустив команду lm (list module), чтобы просмотреть информацию о версии.

randcrash9

Теперь основным подозреваемым стал Nvappfilter, но у меня не было доказательств того, что именно данная библиотека виновата в сбоях. Я продолжил пользоваться системой и проделал те же шаги во время следующих нескольких сбоев. Вне зависимости от того, какое приложение завершало свою работу с ошибкой, стек сбоя всегда был одним и тем же - Nvappfilter вызывал функцию HeapFree. Это все еще не решающее доказательство, но отдельные доказательства были уже налицо.


На данном этапе я решил проверить обновления Nvappfilter, но не знал точно, с каким именно приложением ассоциирована данная библиотека. Я ввел данное имя в поисковик и узнал, что это функция пакета nVidia FirstPacket, которая дает приоритет игровому трафику и входит в состав программного обеспечения для материнских плат nForce.

 

randcrash10

Я зашел на сайт nVidia и загрузил последнюю версию nForce, но пакет не смог обновить Nvappfilter.dll, поэтому сбои продолжались.


В панели управления nVidia я не смог найти способ предотвращающий загрузку Nvappfilter, поэтому мне надо было самому отключить данную функцию. Я не стал использовать функцию FirstPacket, поскольку раньше я и не знал, как ей пользоваться, но для начала мне было нужно понять, как данной библиотеке удалось настроить Windows на свою загрузку. Для этого я запустил программу Autoruns и в меню Winsock Layered Service Provider (LSP) я нашел ссылки на 32- и 64-битные версии Nvappfilter.

 

randcrash11

Я удалил все упоминания о Nvappfilter и с тех пор не было никаких сбоев. Пока я писал данную статью, я снова проверил обновления nForce на предмет обновленной версии Nvappfilter. В новых версии Nvappfilter или любой другой Winsock LSP отсутствует, поэтому предположение о том, что Nvappfilter был виноват в падениях, оказалось верным.


В ходе расследования этого дела я также был вынужден прибегнуть к функциональности локальных дампов в Vista SP1. Поэтому в будущем я буду автоматически получать файлы дампов для расследования при сбое какого-либо приложения. Если вы создадите ключ под названием HKLM\Software\Microsoft\Windows\Windows Error Reporting\LocalDumps, то WerFault всегда будет сохранять дамп. По умолчанию они сохраняются в папку %LOCALAPPDATA%\Crashdumps, но в реестре вы можете изменить данное значение, а также количество сохраняемых WerFault-дампов.

 

Оригинал записи

Posted by abeshkov | 0 Comments

Дело об ошибке FrontPage

В очередной статье из серии "Дело об..." от Марка Руссиновича (Mark Russinovich) мы поговорим об ошибке, вызванной некорректным наследованием прав в Windows.


Представляем вам первую публикацию из серии "Дело об" от стороннего автора. За последние два месяца мы получили множество великолепных статей с расследованиями, но для первого раза мы выбрали это, написанное Троем Вольбринком (Troy Wolbrink), корпоративным веб-мастером.


Трой столкнулся с проблемами со своим сервером и вместо того, перезагрузить его, переустановить его или звонить в Microsoft Product Support Services, где, несомненно, ему бы посоветовали эти же шаги, он использовал базовые техники для решения проблем, на что ему понадобилось несколько минут. В благодарность за детальную статью со скриншотами я послал Трою подписанною копию книги Windows Internals.


В свой доклад Case of the Unexplained..., который я озвучил на TechEd/IT в июне, я включил несколько новых дел. Даже если вы видели мой доклад с ноябрьского TechEd/ITForum, рекомендую вам ознакомиться и с этим, поскольку вы сможете узнать много нового.


Итак, слово Трею.
Недавно я перевел свой сайт с общего хостинга на выделенный сервер. Некоторые части моего сайта использовали FrontPage Server Extensions (FPSE), например, страницы, которые собирали данные и сохраняли их в лог.

frontpage1

Я установил FPSE, используя аплет установки и удаление программ, а потом сделал все, чтобы настроить его с помощью IIS. Но по какой-то причине я не мог правильно настроить FPSE, чтобы моя форма сбора данных работала. Сообщение об ошибке в браузере было абсолютно непонятным.

frontpage2

Я изучил на предмет возможных проблем логи из Event Log сервера, но ничего не нашел.


В мои планы входила замена данного сайта на соответствующий, созданный на ASP.NET и SQL Server, так что я не видел причин, чтобы становится гуру по FPSE для того, чтобы решить одну эту проблему. Но так как другие приоритеты в течение уже нескольких лет мне мешали перейти на ASP.NET, у меня не было другого выбора, кроме как провести расследование. Я как раз недавно смотрел "The Case of the Unexplained…", и решил запустить Process Monitor на своем сервере - возможно, я бы увидел источник проблемы. Я исключил из логов некоторые процессы, которые очевидно, что не могли иметь никакого отношения к моей проблеме. Это удалило много мусора. Так как моя страница называется TntWebLog.htm, а логи пишутся в файл TntWebLog.csv, то я настроил программу так, чтобы она подсвечивала любые события, в пути которых содержится TntWebLog.


Чтобы повторно вызвать появление проблемы я запустил браузер и попытался снова заполнить форму, после чего я прекратил захват событий в Process Monitor. После этого я пролистал список в поиске выделенных строчек. Я удивительно быстро нашел источник проблемы. FPSE пытался создать файл с таким же именем, который уже существовал.

frontpage3

Очевидно, что здесь было что-то не так с правами доступа. Я проверил права доступа к файлу TntWebLog.csv и не нашел в списке учетной записи IUSR_WEBBOARD, которая настроена в IIS для анонимного доступа.

frontpage4

Так что я зашел в расширенные свойства файла и отметил пункт "Allow inheritable permissions from the parent to propagate…", подтвердив свой выбор ОК.

frontpage5

Это действие позволило решить проблемы с безопасностью файла. Я провел тест и убедился, что проблема была решена.


Оглядываясь назад, я могу сказать, что эта проблема произошла из-за того, что я использовал Windows Explorer для перемещения, а не копирования файла. Для подтверждения провел несколько тестов. Когда вы перемещаете файл с помощью Windows Explorer, то Windows Explorer копирует и права доступа, а когда копируете - Windows Explorer создает новый файл, права для которого берет из прав папки. Если бы я изначально копировал этот файл, то проблемы бы этой не было.


Теперь моей первой реакцией будет запустить Process Monitor и посмотреть, что творится в недрах ОС. Удачи в ваших расследованиях!

 

Оригинал записи

Posted by abeshkov | 0 Comments

Дело о пиках загрузки ЦП системным процессом

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

Главным для меня способом контроля за происходящим является автоматический запуск программы Process Explorer при входе в систему. При настройке каждого нового компьютера я добавляю в папку автозапуска в профиле своей учетной записи ярлык на программу Process Explorer с параметром /t, который свертывает ее окно. В результате работу программы Process Explorer выдает лишь значок на панели задач с графиком уровня загрузки ЦП. Так как мне нужен доступ к детальной информации о системных и моих собственных процессах, при работе в ОС Windows Vista я также указываю параметр /e. Каждый раз при входе в систему он заставляет Windows выводить запрос системы контроля учетных записей, который, в свою очередь, позволяет мне предоставить программе Process Explorer права администратора.


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


Однажды я обнаружил, что работа моего нового портативного компьютера, купленного всего несколько месяцев назад, слегка замедляется. Значок программы Process Explorer на панели задачи подтверждал мои ощущения красными мини-графиками загрузки ЦП. При наведении курсора мыши на этот значок выводится название процесса, который больше всего загружает ЦП. В данном случае им оказался процесс System (системный процесс).

clip_image002

Первые несколько раз я замечал эту проблему, но она довольно быстро пропадала сама собой, и я не успевал найти ее причину. Тем не менее, в диалоговом окне System Information (Сведения о системе) программы Process Explorer я мог наблюдать, что пики загрузки ЦП были довольно длительными.

clip_image002[5]

Процесс System, в отличие от других процессов, не размещает исполняемые образы. Он предназначен исключительно для размещения потоков операционной системы для нужд диспетчера памяти, диспетчера кэша и других подсистем, а также для размещения потоков драйверов устройств. Все эти потоки исполняются сугубо в режиме ядра, и именно по этой причине загрузка ЦП процессом System на графиках программы Process Explorer выделяется красным цветом.


Я подозревал, что источником проблемы является какой-то драйвер устройства стороннего производителя, поэтому первым делом мне нужно было выяснить, какой именно поток загружает ЦП. Зная это, я смог бы найти виновника. Я неусыпно ждал появления признаков проблемы при переходе из одной сети в другую, а они не заставили себя ждать слишком долго. Потоки, исполняемые в рамках процесса, показаны в программе Process Explorer на странице Threads (Потоки) диалогового окна Process Properties (Свойства процесса), поэтому в следующий же раз, столкнувшись с пиком загрузки ЦП, я дважды щелкнул на процессе System и открыл страницу Threads (Потоки).

clip_image002[7]

Префикс “ntkrnlpa.exe”, предваряющий начальные адреса потоков, выведенных в верхней части списка потребителей ресурсов ЦП, свидетельствует о том, что они относятся к операционной системе. Ntkrnlpa.exe - это версия ядра, загружаемая в 32-разрядных клиентских системах, поддерживающих технологию защиты No Execute, а также в серверных системах, в которых необходима адресация памяти в объеме свыше 4 ГБ. Поскольку ранее я настроил в программе Process Explorer получение символов, относящихся к образам операционной системы, с общедоступного сервера символов Майкрософт, в списке потоков, помимо прочего, были указаны имена запускавших эти потоки функций. Наиболее активные потоки оказались запущены функцией ExpWorkerThread, что свидетельствовало о том, что это рабочие потоки, действующие от имени системы и драйверов устройств. Вместо того чтобы создавать специальные потоки, потребляющие ресурсы памяти, система и драйверы могут делегировать исполнение задач рабочим потокам операционной системы из общего пула.

Увы, даже зная, что повышенный уровень потребления ресурсов ЦП связан с рабочими потоками, я не продвинулся в установлении первопричины проблемы. Нужно было знать, какие функции вызывают эти рабочие потоки, поскольку функции эти должны были относиться к драйверу устройства или компоненту ОС, от имени которого они исполнялись. Программа Process Explorer предоставляет возможность разобрать структуру исполнения потока, проанализировав его стек. Стеком называется область памяти, в которой хранятся вызовы функций. Чтобы просмотреть стек того или иного потока в программе Process Explorer, нужно сначала выделить этот поток, а затем либо нажать кнопку Stack (Стек), либо дважды щелкнуть на записи потока. Впрочем, в среде Windows Vista попытка просмотреть стек потоков процесса System приводит к выводу ошибки следующего содержания:

clip_image002[9]

Дело в том, что в ОС Windows Vista процесс System относится к числу «защищенных процессов», которые блокируют любой доступ к своим потокам и к занимаемой ими памяти. Защищенные процессы были реализованы с целью подкрепления технологии управления цифровыми правами (DRM). Они позволяют поставщикам видео высокой четкости сохранять ключи шифрования этих материалов так, что вероятность исполнения администратором средств снятия защиты цифровых прав, доступа к процессу и считывания ключей сводится к минимуму.

Поскольку этот путь ни к чему не привел, мне пришлось искать альтернативные способы выяснить назначение рабочих потоков. Для этого я привлек KernRate - инструмент профилирования с командной строкой, который можно совершенно бесплатно загрузить с веб-узла корпорации Майкрософт. Программа KernRate способна профилировать как процессы пользовательского режима, так и потоки режима ядра. Она основывается на механизме профилирования по образцам, реализованном еще в первом выпуске ОС Windows NT. Суть его сводится к записи уникальных адресов, в которых исполняются команды процессора, при срабатывании интервального таймера профилирования. Когда программе Kernrate поступает команда остановить журнал профилирования, она извлекает данные из ядра, отображает адреса на загруженные драйверы устройств и посредством механизма преобразования символов сообщает имена функций.


Подумав, что если программа Kernrate справится с задачей идентификацией драйвера устройства, символы мне не понадобятся, я запустил ее без аргументов. Несмотря на то, что версии программы Kernrate, официально поддерживающей ОС Windows Vista, на данный момент не существует, в 32-разрядных выпусках Windows Vista работает версия этой программы для ОС Windows XP - Kernrate_i386_XP.exe. Кстати сказать, аналогичные задачи профилирования позволяет решать недавно выпущенная служебная программа xperf - она работает в средах Windows Vista и Windows Server 2008, в том числе в 64-разрядных версиях этих ОС. Я запустил профилирование в период заметного увеличения нагрузки на ЦП, а затем, нажав сочетание клавиш CTRL+C, вывел результат на консоль.

clip_image002[11]

В первой позиции списка были указаны обращения к ядру, а вот на втором месте оказался неопознанный драйвер b57nd60x. Поскольку большинство файлов драйверов находится в каталоге %systemroot%\system32\drivers, можно было открыть этот каталог и просмотреть свойства файла с помощью проводника. Но поскольку передо мной была программа Process Explorer, я решил воспользоваться более оперативным способом узнать производителя и версию драйвера. Для этого я открыл процесс System в представлении библиотек DLL. В этом представлении перечисляются библиотеки DLL и файлы, отображенные на адресное пространство процессов пользовательского режима, но применительно к процессу System выводится список модулей ядра, в том числе драйверов, загруженных в системе. Это представление помогло мне установить, что искомый драйвер относится к сетевой карте моего портативного компьютера. Как выяснилось, производитель драйвера - компания Broadcom, а версия - 10.10.

Итак, я знал, что повышенное потребление ресурсов ЦП вызывает драйвер производства компании Broadcom. Теперь нужно было узнать, доступна ли его обновленная версия. Я зашел на веб-узел компании Dell, ознакомился со списком доступных файлов для своей системы, но ничего путного не обнаружил. Подозревая, что производитель не знает о проблеме, я решил обратиться непосредственно к нему. С помощью рабочей группы Майкрософт по взаимодействию с экосистемой оборудования я связался с ответственным специалистом компании Broadcom по драйвером, отравил ему по электронной почте подробное описание симптомов и изложил свои выводы. Он переслал мое письмо разработчику драйвера, который, в свою очередь, подтвердил, что причина описанного мною поведения неизвестна, а через несколько дней отправил мне отладочную версию драйвера с открытыми именами символов с тем, чтобы я выполнил профилирование программой Kernrate и, просмотрев журнал, сообщил, какие функции драйвера активны в периоды пиковой загрузки процессора. Через несколько дней проблема проявилась вновь, и я отправил разработчику выходные данные программы kernrate с информацией об активных функциях.


По словам разработчика, судя по предоставленной мною трассировке, драйвер недостаточно эффективно взаимодействовал с шиной PCIe при обработке определенных запросов, причем проблема, по всей видимости, усугубилась в условиях специфической конфигурации оборудования. Он предоставил мне для испытаний новый драйвер, и по прошествии нескольких недель подробного мониторинга я сообщил ему, что проблема, по всей видимости, решена. Обновленный драйвер пока что не опубликован на веб-узле службы поддержки компании Dell, но я полагаю, что это случится в ближайшем будущем. Так мне удалось раскрыть очередное дело, на этот раз с помощью программ Process Explorer и Kernrate, а также отзывчивого разработчика драйверов из компании Broadcom.

Если вам нравятся записи в моем блоге, посвященные устранению неполадок, рекомендую ознакомиться с веб-трансляцией моего выступления на конференции TechEd/ITforum из серии «Дело о необъяснимом». На протяжении 75-минутной трансляции я привожу примеры устранения неполадок из своего опыта, в том числе пример, который рассмотрен в сегодняшней записи, и многие другие, среди которых и те, которые я еще не описывал. В завершающей части своего сообщения я обращаюсь к аудитории с предложением отправлять мне снимки экрана, журналы и описания успешных случаев устранения неполадок, обещая взамен отправить каждому автору экземпляр своей книги «Внутреннее устройство Windows» с автографом. Предложение еще в силе, так что если у вас есть успешный опыт расследований, зафиксируйте его документально, пришлите мне, и получите бесплатную книгу. Я уже получил немало разного рода историй, и в следующей записи поделюсь с вами одной из них, которую мне прислал один из зрителей веб-трансляции. При непосредственной помощи программы Process Monitor ему удалось решить проблему, связанную с веб-сервером.


Наконец, если вы хотите увидеть мои выступления вживую, приезжайте на конференцию TechEd US/IT Pro, которая пройдет в июне в Орландо. Там я буду выступать с докладами из серий «Дело о необъяснимом», «Изменения в ядре ОС Windows Server 2008» и «Границы системы безопасности Windows». Надеюсь, увидимся!

Оригинал записи

Posted by abeshkov | 0 Comments

Внутреннее устройство Vista SP1 – улучшения в части копирования файлов

В пакете обновления 1 (SP1) для ОС Windows Vista, если сравнивать его с первоначальным выпуском Vista, наблюдается ряд изменений в сферах совместимости приложений, поддержки устройств, управления питанием, безопасности и надежности. Подробный список таких изменений изложен в документе «Заметные изменения в пакете обновления 1 (SP1) для ОС Windows Vista» (на английском языке), который можно загрузить здесь. В частности, упомянутый документ повествует об увеличившейся производительности копирования файлов в некоторых сценариях, как то создание локальных копий в пределах одного диска, копирование файлов с удаленных машин, работающих под управлением других ОС, и копирование файлов между системами, оснащенными ОС Windows Vista с пакетом обновления 1 (SP1). За счет чего же удалось достичь таких результатов? Ответ на этот вопрос весьма нетривиален. Все дело в изменениях механизма копирования файлов в Windows Vista по сравнению с Windows XP, с одной стороны, и в дальнейших усовершенствованиях, внесенных в Windows Vista пакетом обновления 1 (SP1), с другой. Поскольку копировать файлы приходится всем, мне подумалось, что будет нелишне, отвлекшись на время от разбора «дел», проследить развитие механизма копирования файлов и понять, каким же образом возросла его производительность в пакете обновления 1 (SP1).


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

Механизм копирования файлов в предыдущих версиях Windows
Механизм копирования файлов Windows нацелен на успешную работу в любых сценариях – настолько, насколько это вообще возможно, учитывая неизбежность компромиссных решений и нехватку значимой информации. До появления ОС Windows Vista механизм был тривиален. Исходный и конечный файлы открывались в режиме кэширования, затем исходный файл последовательно считывался фрагментами по 64 КБ (при создании сетевых копий вследствие ограничений по размеру блоков чтения, налагаемых протоколом SMB1.0, размер фрагмента уменьшался до 60 КБ), и эти фрагменты передавались в конечный файл. При доступе к файлу путем ввода-вывода с кэшированием (в отличие от ввода-вывода в режиме отображения в памяти и ввода-вывода без буферизации) данные, подлежащие чтению и записи, сохраняются в памяти как минимум до того момента, когда диспетчер памяти решит, что эта память нужна для других целей (в частности, для кэширования данных других файлов).
Асинхронное упреждающее чтение в ходе копирования производилось диспетчером кэша Windows. Пока исходный файл считывался в фоновом режиме, проводник записывал данные на другом диске или в удаленной системе. Посредством механизма записи с задержкой, реализованной диспетчером кэша, содержимое скопированного файла своевременно перемещалось из памяти на диск. Таким образом, при необходимости ресурсы памяти можно было направить на решение других задач, а в случае неисправности диска или сбоя системы ущерб от потери данных должен был быть минимальным. Действие описанного алгоритма наглядно демонстрирует следующая трассировка, сделанная программой Process Monitor. Она показывает, как файл размером 256 КБ в среде Windows XP копируется из одного каталога в другой, а для выделения операций чтения и записи включены соответствующие фильтры.

clip_image002

Первому событию соответствует предпринятая проводником попытка считывания данных, отсутствующих в памяти. В связи с этим диспетчер кэша осуществляет ввод-вывод без кэширования (чтение или запись данных напрямую с диска или на диск без кэширования в памяти). Выборка данных с диска соответствует событию 1 (см. трассировку стека ниже).

clip_image002[4]

Согласно трассировке стека, вызов ReadFile проводником осуществляется в строке 22 посредством функции BaseCopyStream, а диспетчер кэша опосредованно вызывает операцию чтения без кэширования, воздействуя на отображение файла в памяти и вызывает ошибку страницы в строке 8.


Так как проводник открывает файл с рекомендацией о последовательном доступе (не отраженной в трассировке), то поток чтения с опережением диспетчера кэша, исполняемый в рамках процесса System, начинает агрессивное чтение файла от имени проводника (см. события 2 и 3). Функции чтения с опережением показаны в событии 2 трассировки стека.

clip_image002[6]

Вероятно, вы заметили, что операции чтения с опережением первоначально осуществляются вне последовательности, которая была задана исходным чтением без кэширования, инициированным первой операцией чтения проводника. Такая ситуация может привести к дополнительному позиционированию головки диска и снижению производительности. Впрочем, когда проводник обнаруживает данные, ранее считанные диспетчером кэша, а его запросы на чтение начинают обслуживаться из памяти, он прекращает инициировать операции ввода-вывода без кэширования. Как правило, в ходе копирования файлов диспетчер кэша опережает проводник на 128 КБ.


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


Какие изменения механизм копирования файлов претерпел с выходом Windows Vista
В процессе работы над ОС Windows Vista группа разработки продукта внесла в механизм копирования файлов изменения, призванные оптимизировать его работу в ряде важнейших сценариев. Один из самых значительных огрехов в реализации этого механизма заключается в том, что при копировании данных большого объема поток записи с задержкой диспетчера кэша в конечной системе зачастую не поспевает за записью данных и их кэшированием в памяти. При этом данные переполняют память, заставляя удалять из неё другие полезные данные и код. В конечном счете память становится туннелем, через который данные передаются со скоростью, заданной возможностями диска. 


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


С такими сравнительно компактными и чередующимися операциями с файлами связана определенная проблема. Дело в том, что драйвер файловой системы SMB, реализующий протокол удаленного общего доступа к файлам Windows, не поддерживает конвейерную обработку данных в сетях с высокой пропускной способностью и значительной задержкой передачи данных (WLAN). Каждый раз, когда локальная система ожидает получения данных удаленной системой, передача данных замедляется, и копирование неизбежно сопровождается задержкой, связанной с обменом подтверждениями и ожиданием последующих блоков данных.


Изучив различные альтернативы, для решения выявленных проблем разработчики решили реализовать механизм копирования, ориентированный на большие асинхронные операции ввода-вывода без кэширования. При вводе-выводе без кэширования данные копируемых файлов не занимают место в памяти локальной системы, а значит, её содержимое сохраняется. Асинхронные операции ввода-вывода крупных файлов позволяют организовать конвейерную обработку данных в сетях со значительной задержкой. Нагрузка на процессор сокращается в связи с тем, что диспетчеру кэша не приходится заниматься распределением памяти. Решение перейти на ввод-вывод без кэширования было принято отчасти из-за неэффективной обработки первоначальной версией диспетчера кэша ОС Windows Vista операций ввода-вывода крупных файлов. Размер операций ввода-вывода все же ограничен. Это связано с тем, что перед записью данных механизму копирования необходимо выполнить их чтение, причем эти две операции желательно производить одновременно, что особенно актуально при копировании между разными дисками или системами. Крупные операции ввода-вывода сложны с точки зрения корректной оценки их продолжительности, поскольку точек измерения хода операции и обновления оценки меньше, чем в других случаях. Не остался незамеченным разработчиками и существенный недостаток ввода-вывода без кэширования – при копировании большого количества небольших файлов головка диска постоянно перемещается от исходного файла к конечному, затем обратно к исходному и т.д.
По результатам длительного анализа, сравнения эффективности и корректировки разработчики реализовали алгоритм, предусматривающий для файлов размером менее 256 КБ ввод-вывод с кэшированием. При работе с файлами размером свыше 256 КБ механизм обращается к внутренней таблице и с её помощью определяет количество и размер блоков ввода-вывода без кэширования, которые он сможет единовременно обработать. Число таких блоков варьируется от 2 при копировании файлов размером менее 2 МБ до 8 при копировании файлов крупнее 8 МБ. Размер блока ввода-вывода равен размеру файла, если файл меньше 1 МБ. Для файлов размером до 2 МБ он составляет 1 МБ, а для более крупных файлов – 2 МБ.


К примеру, чтобы скопировать файл размером 16 МБ, механизм копирования инициирует восемь асинхронных операций чтения исходного файла без кэширования по 2 МБ на каждую, дожидается их завершения, затем инициирует восемь асинхронных операций записи в конечный файл (опять же без кэширования), дожидается их завершения, после чего повторяет цикл. Эта модель хорошо просматривается в выполненной программой Process Monitor трассировке копирования файла размером 16 МБ с локальной на удаленную систему.

clip_image002[8]

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

clip_image002[10]

Обратите внимание, что смещение операции записи меняется сразу с 327 680 на 458 752, а блок со смещением 393 216 оказывается пропущен. Этот пропуск вызывает повторное позиционирование головки диска, а файловая система NTFS инициирует дополнительную операцию записи в пропущенной области для обнуления части файла. Именно поэтому на смещение 393 216 приходятся две операции записи. В трассировке стека, соответствующей выделенному событию, видно, как NTFS вызывает функцию CcZeroData диспетчера кэша, чтобы обнулить пропущенный блок.

clip_image002[12]

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


Вероятно, самый значительный недостаток рассматриваемого алгоритма, на который жаловались многие пользователи ОС Windows Vista, заключается в том, что при копировании большого набора файлов размером от 256 КБ до нескольких десятков мегабайт воспринимаемая производительность иногда оказывается существенно ниже, чем в ОС Windows XP. Дело в том, что файловый ввод-вывод с кэшированием, реализованный в старом алгоритме, позволял проводнику записывать конечные файлы в память и закрывать диалоговое окно копирования задолго до того, как поток записи с задержкой диспетчера кэша фактически сохранял данные на диске. Теперь, когда в ОС Windows Vista реализован алгоритм без кэширования, проводник вынужден перед инициированием каждой последующей операции дожидаться завершения операции текущей, а для того, чтобы сообщить о завершении операции копирования файлов, необходимо, чтобы все скопированные данные фактически оказались на диске. Кроме того, проводник в Windows Vista ждет 12 секунд перед оценкой продолжительности операции копирования. При этом сам алгоритм оценки чувствителен к колебаниям скорости копирования. Сочетание этих двух факторов усиливает недовольство пользователей медленным копированием.


Улучшения в пакете обновления 1 (SP1)
В ходе разработки пакета обновления 1 (SP1) для ОС Windows Vista участники группы разработки решили пересмотреть механизм копирования, чтобы найти способы улучшения фактической и воспринимаемой производительности операций копирования в ситуациях, с которыми новая реализация справлялась неудовлетворительно. Наиболее значимым стало их решение возвратиться к файловому вводу-выводу с кэшированием при копировании всех локальных и удаленных файлов за одним лишь исключением, о котором я вскоре расскажу. Кэширование позволило сократить воспринимаемое время копирования и повысить производительность в сценариях публикации. Для того, чтобы преодолеть вышеописанные недостатки ввода-вывода с кэшированием, потребовалось внести существенные изменения как в алгоритм копирования файлов, так и в платформу.


Тот самый исключительный случай, когда механизм копирования файлов ОС Windows Vista с пакетом обновления 1 (SP1) не прибегает к кэшированию, связан с копированием удаленных файлов. Проблема двукратного кэширования в этом случае решается при помощи клиентского драйвера удаленной файловой системы Windows –Rdbss.sys. Этому драйверу отправляется команда, препятствующая кэшированию удаленного файла в локальной системе в ходе его чтения или записи. Запуск этой команды проводником виден в следующем фрагменте журнала программы Process Monitor.

clip_image002[14]

Еще одно улучшение в части копирования файлов на удаленную систему связано с конвейерным вводом-выводом, который инициируется драйвером файловой системы SMB2 – srv2.sys, впервые появившемся в ОС Windows Vista и Windows Server 2008. Если в первоначальной реализации протокола SMB по сети передавались блоки ввода-вывода размером 60 КБ, то в версии SMB2 им на смену пришли блоки размером 64 КБ с поддержкой конвейеризации. В результате, принимая от приложения крупный блок ввода-вывода, протокол может одновременно инициировать множество блоков по 64 КБ, а значит, передача данных в удаленную систему и из неё происходит с меньшей задержкой.


Кроме того, механизм копирования инициирует четыре начальных блока ввода-вывода в размере от 128 КБ до 1 МБ (в зависимости от размера копируемого файла). После этого поток чтения с опережением диспетчера кэша начинает инициировать крупные операции ввода-вывода. Изменения, внесенные в платформу в ходе разработки пакета обновления 1 (SP1), касаются диспетчера кэша и позволяют ему обрабатывать более крупные операции ввода-вывода с помощью чтения с опережением и записи с задержкой. Укрупнение блоков ввода-вывода стало возможным лишь благодаря работе, проведенной при разработке первоначальной версии системы ввода-вывода ОС Windows Vista. Эта работа была направлена на поддержку блоков размером свыше 64 КБ и тем самым на снятие ограничения, характерного для предыдущих версий ОС Windows. Ввод-вывод большими блоками повышает производительность и при локальном копировании, так как сокращается частота обращений к диску и операций позиционирования головки. Кроме того, он помогает потоку записи с задержкой диспетчера кэша поспевать за скоростью заполнения памяти скопированными данными файлов. Это уменьшает, хотя и не исключает вероятность критической нехватки памяти, при которой активное содержимое памяти в ходе копирования уничтожается. Наконец, при удаленном копировании крупные блоки ввода-вывода позволяют драйверу SMB2 задействовать конвейерную обработку. Диспетчер кэша может инициировать блоки ввода-вывода на чтение, которые по размеру в два раза больше блоков, генерируемых приложениями – до 2 МБ в Windows Vista и до 16 МБ в Windows Server 2008. Блоки ввода-вывода на запись в Windows Vista могут достигать 1 МБ, а в Windows Server 2008 – 32 МБ.


Нижеследующая трассировка демонстрирует фрагмент операции копирования файла размером 16 МБ с одной системы под управлением Windows Vista SP1 в другую. Проводник инициирует блоки ввода-вывода размером 1 МБ, а поток чтения с опережением диспетчера кэша (он обозначен флагом ввода-вывода без кэширования) обрабатывает блоки размером 2 МБ.

clip_image002[16]

Изменения, реализованные в пакете обновления 1 (SP1) для ОС Windows Vista, хоть и обеспечивают в целом более высокую производительность, чем предыдущие версии Windows, но в некоторых специфических случаях производительность может быть ниже, чем в первоначальной версии Windows Vista. Первый такой случай – копирование в удаленную систему с ОС Windows Server 2003 или копирование из такой системы по медленному сетевому соединению. Механизм копирования в первоначальной версии Windows Vista справился бы с задачей быстро, но в связи с вышеупомянутой проблемой нарушения очередности операций ввода-вывода поведение диспетчера кэша системы с ОС Windows Server 2003 привело бы к заполнению памяти сервера данными копируемого файла. Изменения, внесенные в механизм копирования при разработке пакета обновления 1 (SP1), помогают решить эту проблему, однако в силу того, что размер блоков ввода-вывода сократился с 60 КБ до 32 КБ, пропускная способность в условиях соединения со значительной задержкой оказывается примерно в два раза ниже аналогичного показателя в первоначальной версии Windows Vista.


Другой сценарий, при котором механизм копирования в реализации пакета обновления 1 (SP1) уступает по производительности первоначальной версии Windows Vista, связан с копированием больших объемов данных в рамках одного раздела. Так как в пакете обновления 1 (SP1) блоки ввода-вывода меньше (в основном, это сделано для того, чтобы предоставить другим компонентам системы беспрепятственный доступ к диску, а значит, повысить реактивность во время копирования), головка диска в период между чтением из исходных файлов и записью в файлы конечные позиционируется чаще. Это особенно ощутимо при работе с дисками, которые не оснащены внутренними алгоритмами организации очередей, позволяющими оптимизировать позиционирование.


Стоит заметить, что с появлением пакета обновления 1 (SP1) проводник стал рассчитывать время копирования гораздо быстрее, чем в первоначальном выпуске Windows Vista, а алгоритм расчета стал более точным.

Резюме
Копирование файлов – не настолько простая операция, как это может показаться на первый взгляд. Группа разработки ОС Windows Vista очень серьезно отнеслась к отзывам пользователей и провела не одну сотню часов, пробуя различные подходы и корректируя конечную реализацию для решения поставленной задачи – восстановить производительность большинства сценариев копирования как минимум на уровне предыдущих версий Windows и радикально повысить производительность в ряде важнейших сценариев. Изменения равным образом действительны при копировании как через проводник, так и посредством сторонних приложений, работающих с API CopyFileEx. Наиболее серьезных улучшений по сравнению с предыдущими версиями ОС Windows удалось достичь при копировании файлов в сетях со значительной задержкой и высокой пропускной способностью. В таких условиях благодаря крупным блокам ввода-вывода, конвейерной обработке ввода-вывода протоколом SMB2 и автонастройке окна получения стека TCP/IP те задачи, которые в ОС Windows XP или Windows Server 2003 заняли бы десять минут, теперь решаются в течение минуты. Недурственно.

Оригинал записи

Posted by abeshkov | 0 Comments
More Posts Next page »
 
Page view tracker