В какой момент региону передают физическую память
Допустим, Вы разрабатываете программу — электронную таблицу, которая поддерживает до 200 строк при 256 колонках. Для каждой ячейки необходима своя структура CELLDATA, описывающая ее (ячейки) содержимое. Простейший способ работы с двухмерной матрицей ячеек, казалось бы, — взять и объявить в программе такую переменную:
CELLDATA CellData[200][256];
Но если размер структуры CELLDATA будет хотя бы 128 байтов, матрица потребует 6 553 600 (200 * 256 * 128) байтов физической памяти. Не многовато ли? Тем более что большинство пользователей заполняет данными всего несколько ячеек. Выходит, матрицы здесь крайне неэффективны.
Поэтому электронные таблицы реализуют на основе других методов управления структурами данных, используя, например, связанные списки. В этом случае структуры CELLDATA создаются только для ячеек, содержащих какие-то данные. И поскольку большая часть ячеек в таблице остается незадействованной, Вы экономите колоссальные объемы памяти. Но это значительно усложняет доступ к содержимому ячеек. Что бы, допустим, выяснить содержимое ячейки на пересечении строки 5 и колонки 10, придется пройти по всей цепочке связанных списков. В итоге метод связанных списков работает медленнее, чем метод, основанный на объявлении матрицы.
К счастью, виртуальная память позволяет найти компромисс между "лобовым" объявлением двухмерной матрицы и реализацией связанных списков. Тем самым можно совместить простоту и высокую скорость доступа к ячейкам, предлагаемую "матричным" методом, с экономным расходованием памяти, заложенным в метод связанных списков.
Вот что надо сделать в своей программе.
Теперь, спроецировав физическую память на нужный участок зарезервированного региона, программа может обратиться к нему, не вызвав при этом нарушения доступа. Таким образом, метод, основанный на использовании виртуальной памяти, самый оптимальный, поскольку позволяет передавать физическую память только по мере ввода данных в ячейки электронной таблицы. И ввиду того, что большая часть ячеек в электронной таблице обычно пуста, то и большая часть зарезервированного региона физическую память не получает.
Но при использовании виртуальной памяти всс же возникает одна проблема приходится определять, когда именно зарезервированному региону надо передавать физическую память. Если пользователь всего лишь редактирует данные, уже содержащиеся в ячейке, в передаче физической памяти необходимости нст — это было сделано в момент первого заполнения ячейки.
Нельзя забывать и о размерности страниц памяти. Попытка передать физическую память для единственной структуры CELLDATA (как в п. 2 предыдущего списка) приведет к псрсдачс полной страницы памяти Но в этом, как ни странно, есть свое преимущество: передав физическую память под одну структуру CELLDATA, Вы одновременно выделите ее и следующим структурам CELLDATA. Когда пользователь начнет заполнять следующую ячейку (а так обычно и бывает), Вам, может, и не придется передавать дополнительную физическую память.
Определить, надо ли передавать физическую память части региона, можно четырьмя способами.
Если да, больше ничего не делать, нет — вызвать VirtuaiAlloc для передачи памяти. Этот метод на деле еще хуже, чем первый он не только замедляет выполнение, но и увеличивает размер программы из-за дополнительных вызовов VirtualQuery.