Преодолевая границы Windows: объекты USER и GDI (ч.1)

Автор: Topol Четверг, Май 3rd, 2012 Нет комментариев

Рубрика: Операционные системы

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

Как всегда, я рекомендую вам прочитать предыдущие мои публикации, прежде чем перейти к этой статье, поскольку некоторые ограничения, связанные с ресурсами USER и GDI, основаны на уже описанных мною ограничениях. Вот полный список других моих статей из серии «Преодолевая границы Windows»:

Сеансы, рабочие станции и рабочие столы
Есть несколько понятий, которые могут облегчить понимание связи между объектами USER, GDI и системой. Первое из них — понятия сеанса. Сеанс представляет интерактивный вход в систему пользователя, обладающего собственной клавиатурой, мышью и дисплеем, и обозначает границы ресурсов и защиты.

Понятие «сеанс» впервые было представлено в терминальных службах (ныне «службах удаленного рабочего стола») в Windows NT 4 Terminal Server Edition, где понятия физического дисплея, клавиатуры и мыши виртуализировались для каждого пользователя, удаленно совершившего интерактивный вход в систему, и основной функционал терминальных служб был встроен в Windows 2000 Server. В Windows XP сеансы были усилены для создания функции быстрого переключения пользователей (от англ. Fast User Switching, FUS), которая позволяет вам переключаться между несколькими интерактивными логинами на одном физическом дисплее, клавиатуре и мыши.

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

Каждый процесс однозначно связан с определенным сеансом, что вы можете увидеть, добавив колонку Session в Sysinternals Process Explorer. Этот скриншот, на котором я свернул дерево процессов, чтобы показать только процессы, не имеющие родителей, сделан из системы Remote Desktop Services (RDS — ранее Terminal Server Services), которая имеет четыре активных сеанса: сеанс 0 является выделенным сеансом, в котором выполняются системные процессы на Windows Vista и выше; сеанс 1 — это сеанс, в котором я пишу эту статью; сеанс 2 — это сеанс другой учетной записи пользователя, под которой я одновременно совершил вход из другой системы; и наконец, сеанс 3 является одним из сеансов, которые создает Remote Desktop Services для того, чтобы быть готовой к следующим интерактивным входам в систему:

Так как каждый процесс связан с определенным сеансом и операционной системе обычно необходимо иметь доступ к данным текущего сеанса процесса, Windows определяет представление к данным сеанса процесса в виртуальном адресном пространстве процесса. Таким образом, когда система переключается между потоками различных процессов, она также переключает адресные пространства через переключение текущего представления сеанса. Например, когда процесс Csrss.exe сеанса 0 является текущим процессом, сопоставления адресного пространства включают в себя системное адресное пространство (в которое включены все адресные пространства процессов), адресное пространство Csrss и адресное пространство нулевого сеанса. Область памяти, сопоставляющая данные сеанса, также известна как «пространство представления сеанса» (в ориг. Session View Space) или просто «пространство сеанса» (в ориг. Session Space). Когда система переключается на поток из процесса Explorer сеанса 1, соответственно изменяются сопоставления, и когда она переключается на поток Блокнота, пространство сеанса сеанса 1 остается сопоставленным:

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

Следующими понятием является рабочий стол - объект, определенный диспетчером окна для представления виртуального дисплея, который включает в себя окна, связанные с этим рабочим столом (обратите внимание, что данное определение отличается от того, которое имеет рабочий стол Explorer, являющийся пользовательской папкой с ярлыками и другими объектами, помещенными туда пользователем). Рабочий стол, заданный по умолчанию, имеет название «Default», однако приложения могут создавать дополнительные рабочие столы и переключать подключение с логическим дисплеем; утилита Sysinternals Desktops может создавать до четырех виртуальных рабочих столов, между которыми может переключаться пользователь.

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

Вы можете увидеть рабочие станции, связанные с нулевым сеансом, просмотрев пространство имен Object Manager в папке Windows с помощью инструмента Sysinternals Winobj (просмотр этой папки требует наличия прав администратора). Здесь вы можете увидеть, что рабочая станция Microsoft Windows Search Service создается, чтобы выполнять фильтры поиска, рабочие станции для каждой из трех встроенных служебных учетных записей (System, Network Service и Local Service) и интерактивную рабочую станцию нулевого сеанса:

В папке Sessions в пространстве имен Object Manager вы можете видеть рабочие станции, связанные с другими сеансами. Вот лишь одна из этих рабочих станций, интерактивная рабочая станция WinSta0, связанная с моим сеансом входа в систему:

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

Помимо наличия связи с определенными сеансами, процессы связаны с определенной рабочей станцией и рабочим столом, хотя процессы могут переключаться между ними обоими, а потоки могут переключать между рабочими столами. Таким образом, каждая связь процесса может быть представлена в виде иерархического пути (например, так «Session 1WinSta0Default»). В большинстве случаев вы можете косвенно определить, к какой рабочей станции или рабочему столу подключен процесс, просмотрев его таблицу дескрипторов в окне дескрипторов Process Explorer, чтобы увидеть имена открытых им объектов. Этот скриншот таблицы дескрипторов процесса Explorer показывает, что данный процесс подключен к рабочему столу Default на рабочей станции WinSta0 сеанса 1:

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

Базовое ограничение, накладываемое диспетчером окон, состоит в том, что ни один процесс не может создать более 10000 объектов USER. Это ограничение пытается воспрепятствовать тому, чтобы один исчерпал ресурсы, связанные с объектами USER, либо из-за того, что он запрограммирован с использованием алгоритмов, допускающих создание чрезмерного числа объектов, либо потому, что он допускает утечку объектов, создавая их и не удаляя их после того, как в них отпадает надобность. Вы можете легко проверить наличие данного ограничения, запустив утилиту Sysinternals Testlimit с параметром -u, который указывает Testlimit создать столько объектов USER, сколько она может:

Диспетчер окон отслеживает количество объектов USER, которые может расместить процесс, что вы можете увидеть, добавив колонку USER Objects в отображение Process Explorer; таким образом, вы можете следить за количеством объектов, которое может разместить объект. Этот скриншот показывает, что системные (например, Lsass.exe, Local Security Authority Subsystem) и служебные (например, Svchost) процессы Windows не могут размещать объекты USER, поскольку они не имеют пользовательского интерфейса:

На странице Performance диалогового окна свойств процесса в Process Explorer отображается число объектов USER, размещенных процессом:

Фундаментальное ограничение на количество объектов USER появилось на основании того факта, что их идентификаторы в первых версиях Windows являлись 16-битными, как и сами Windows. Когда в последующие версии была добавлена поддержка 32-битной адресации, идентификаторы USER продолжали оставаться ограниченными 16-битными значениями, чтобы 16-битные процессы могли взаимодействовать с окнами и другими объектами USER, созданными 32-битными процессами. Таким образом, 65535 (2^16) является ограничением на общее число объектов USER, которые могут быть созданы в одном сеансе (и, по историческим причинам, окна должны иметь четные идентификаторы, так что максимально в одной сессии может быть создано 32768 окон). Вы можете проверить наличие этого ограничения, запуская несколько копий Testlimit с параметром -u до тех пор, пока это будет возможно. Предполагая, что процессы, которые уже запущены у вас, не используют слишком много объектов, у вас должно получиться запустить 7 копий, из которых первые шесть разместят по 10000 объектов и последняя разместит количество объектов, равное разнице между количеством уже размещенных объектов и 65535:

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

Пока что я говорил только об ограничениях, связанных с абсолютным числом объектов USER, которые может разместить процесс или рабочая станция, но есть и другие ограничения, связанные с дисковым пространством, используемым под сами объекты USER. Каждый рабочий стол имеет свою собственную область памяти, называемую кучей рабочего стола (от англ. desktop heap), из которой выделено большинство объектов USER, созданных на рабочем столе. Поскольку кучи хранятся в пространстве сеанса и 32-битное адресное пространство накладывает ограничение на объем адресного пространства режима ядра, размеры куч рабочего стола ограничены довольно малым объемом. Они также различаются по размеру в зависимости от типа рабочего стола, для которого они предназначены, и в зависимости от разрядности системы (32-х или 64-х битная).

В своих статьях «Обзор кучи рабочего стола» и «Куча рабочего стола, ч. 2″ из блога NT Debugging Мэтью Джастис (Matthew Justice) проделал великолепную работу по документированию размеров куч рабочего стола вплоть до Windows Vista SP1. В данной таблице собранны данные о размере куч рабочего стола для различных версий Windows вплоть до Windows Server 2008 R2:

Версия ОС Interactive Desktop Non-Interactive Desktop Winlogon Desktop Disconnect Desktop
Windows XP (32-бит) 3 MB 512 KB 128 KB 64 KB
Windows Server 2003 (32-бит) 3 MB 512 KB 128 KB 64 KB
Windows Server 2003 (64-бит) 20 MB 768 KB 192 KB 96 KB
Windows Vista/Windows Server 2008 (32-бит) 12 MB 512 KB 128 KB 64 KB
Windows Vista/Windows Server 2008 (64-бит) 20 MB 768 KB 192 KB 96 KB
Windows 7 (32-бит) 12 MB 512 KB 128 KB 64 KB
Windows 7/Windows Server 2008 R2 (64-бит) 20 MB 768 KB 192 KB 96 KB

Здесь стоит отметить, что у первоначального релиза 32-битной Windows Vista размер интерактивной кучи равен 3 Мб, как и у предыдущих 32-битных версий Windows. После ее релиза наша телеметрия показа нам, что некоторым пользователям иногда не хватает этого объема, возможно потому, что они запускают много приложений на системе с большим объемом памяти, так что в SP1 это значение было увеличено до 12 Мб. Также возможно переопределить стандартные размеры кучи рабочего стола с помощью настройки системного реестра, описанной в статье Мэтью.

В версиях Windows, предшествующих Windows Vista, вы можете использовать инструмент Microsoft Desktop Heap Monitor, чтобы увидеть размер куч рабочего стола, и какая часть из них используется. По этому результату работы этого инструмента на системе с 32-битной Windows XP видно, что было использовано только 5,6% от кучи (172 Кб) интерактивного рабочего стола Default.

Данный инструмент не был обновлен для Windows Vista, поскольку использование большего размера кучи рабочего стола в новых версиях Windows означает, что объем кучи рабочего стола крайне редко будет исчерпываться, прежде чем будут достигнуты другие ограничения объектов USER. Однако, вы можете использовать Testlimit с параметрами -u и -i, чтобы увидеть, как ведет себя система при истощении кучи рабочего стола. Данная комбинация параметров Testlimit создает структуры данных класса window, у которых есть 4 Кб дополнительного дискового пространства, прежде чем они вызовут ошибку. Вот результат работы Testlimit, запущенной сразу после того, как я сделал скриншот вывода Desktop Heap Monitor. 2823 Кб и 172 Кб, которые, согласно Desktop Heap Monitor, уже были выделены, в сумме дают приблизительно 3 Мб:

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

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

Источник: thevista.ru

Оставить комментарий

Чтобы оставлять комментарии Вы должны быть авторизованы.

Похожие посты