В unix подобных операционных системах в качестве дополнительной памяти используется
Оригинал: "6. Paging"
Автор: James Molloy
Дата публикации: 2008
Перевод: Н.Ромоданов
Дата перевода: январь 2012 г.
В этой главе мы собираемся добавить к системе страничную организацию памяти. Это режим работы с памятью предназначен для двух целей - защите памяти и реализации виртуальной памяти (которые на практике неразрывно взаимосвязаны).
Типы памяти
Не все память, выделенная в пространстве виртуальной памяти, одинакова. Мы можем классифицировать его по двум осям:
- первая ось — это то, является ли память частной (специфичной для этого процесса) или общей,
- вторая ось — это то, является ли память файловой или нет (в этом случае говорят, что она анонимная).
Это создает классификацию с 4 классами памяти:
PRIVATE | SHARED | |
ANONYMOUS | 1 | 2 |
FILE-BACKED | 3 | 4 |
Выделение
Выделение Чтобы выделить объект, необходимо включить режим выделения (см. предыдущий подраздел). Для выделения одиночного объекта следует щелкнуть по нему указателем мыши. Вокруг этого объекта появится рамка с маркерами. Рамки для прямоугольника, эллипса и текста
Выделение дескриптора памяти
Выделение дескриптора памяти Указатель на дескриптор памяти, выделенный для какой-либо задачи, хранится в поле mm дескриптора процесса этой задачи. Следовательно, выражение current->mm позволяет получить дескриптор памяти текущего процесса. Функция copy_mm() используется для
Файловые системы
Файловые системы Как известно ещё с советских атеистических времен, Господь Бог, создавая человека, хотел сделать его умным, честным и партийным. Но оказалось, что даже он, при всём своём всемогуществе, не смог ему дать больше двух качеств вместе.Аналогично и с файловыми
Private
Память, специфичная для процесса. Таковой является большая часть памяти, с которой вы работаете (стек, куча, статические переменные).
Поскольку изменения, сделанные в частной памяти, не видны другим процессам, они являются предметом COW. В качестве побочного эффекта это означает, что даже если память является частной, несколько процессов могут совместно использовать одну и ту же физическую память для хранения данных. Например, это касается двоичных файлов программ и разделяемых библиотек.
Общим заблуждением является то, что KDE занимает много оперативной памяти, потому что каждый отдельный процесс загружает Qt и KDElib, однако благодаря механизму COW все процессы будут использовать ту же физическую память для частей этих библиотек, предназначенных только для чтения.
В случае файловой частной памяти изменения, сделанные процессом, не записываются обратно в основной файл, однако изменения, внесенные в файл, могут быть или могут не быть доступны для процесса.
Shared
Общая память — это нечто, предназначенное для взаимодействия между процессами. Она может быть создана только путем явного запроса с помощью правильного вызова mmap() или отдельного вызова (shm*). Когда процесс записывает в общую память, модификация видна всем процессам, которые отображают себе в адресные пространства эту же память.
В случае, если память является file-backed, любой процесс, отображающий файл, будет видеть изменения в файле, поскольку эти изменения распространяются через сам файл.
Глобальные файловые системы
Глобальные файловые системы Я испытываю особый интерес к файловым системам, поддерживающим устройства хранения информации подключенные к сети. Когда мы начнем разделять диски между несколькими системами в сети, скорость доставки данных станет очень важным фактором.
23.2.2. Функции для работы с памятью
23.2.2. Функции для работы с памятью Функции для работы с памятью библиотеки Glib выполняют те же действия, что и соответствующие им функции языка С. Вот их прототипы:gpointer g_malloc(gulong size);gpointer g_realloc(gpointer mem, gulong size);void g_free(gpointer
14.1. Выделение выровненной памяти: posix_memalign() и memalign()
14.1. Выделение выровненной памяти: posix_memalign() и memalign() Для большинства задач отлично подходят стандартные процедуры выделения памяти — malloc(), realloc() и т.д. Но иногда может понадобиться память, которая выровнена тем или иным способом. Другими словами, адрес первого выделенного
vmtouch
Это небольшой инструмент для изучения и управления page cache'ем (кешем файловой системы) UNIX-подобных систем.
2.3.2. Файловые системы
2.3.2. Файловые системы Теперь поговорим о файловых системах, с которыми работает Linux. Эта ОС поддерживает множество систем, в том числе и Windows-файловые системы FAT, FAT32 и NTFS, но при установке ОС Linux желательно выбрать родную систему Ext2, Ext3 или ReiserFS (это название часто сокращают
3.10. Как ускорить работу с памятью?
3.10. Как ускорить работу с памятью? Можно регулировать несколько значений реестра для ускорения работы подсистемы памяти XP. Но будьте осторожны, так как неправильные значения могу привести к неработоспособности системы. Вы можете изменить некоторые значения реестра в
6.1. Виртуальная память (теория)
Если вы знаете, что такое виртуальная память, вы можете пропустить этот раздел.
Если в linux вы создадите крошечную программу, например,
, откомпилируете ее, а затем запустите 'objdump -f', вы можете увидеть нечто, похожее на следующее:
Обратите внимание на начальный адрес программы 0x80482a0, что эквивалентно приблизительно 128 Мб в адресном пространстве. Может показаться странным, но эта программа будет работать отлично на машинах с объемом оперативной памяти, меньшем 128 Мб.
То, что программа на самом деле «видит», когда она читает из памяти и пишет в память, является виртуальным адресным пространством. Часть виртуального адресного пространства отображается в физическую память, а часть - не отображается. Если вы пытаетесь получить доступ к неотображаемой части, то процессор выдаст сигнал о некорректном обращении к памяти page fault, операционная система ловит его, и в POSIX-системе выдает сигнал SIGSEGV, за которым непосредственно следует сигнал SIGKILL.
Эта абстракция является чрезвычайно полезной. Это означает, что с помощью компиляторов можно создавать программы, которые будут, когда запускаются, размещать код в конкретном месте в памяти. При использовании виртуальной памяти процесс считает, что он, например, находится по адресу 0x080482a0, но на самом деле это может быть место в физической памяти с адресом 0x1000000. В результате процессы не могут случайно (или намеренно) испортить данные других процессов.
Виртуальная память этого типа полностью зависит от поддержки аппаратным обеспечением. Ее нельзя эмулировать программно. К счастью, в архитектуре x86 есть именно такая возможность. Этот модуль называется MMU (Memory Management Unit- Устройство управление памятью) и он обрабатывает все операции по отображению памяти, связанные с сегментацией и страничной организацией памяти, образуя слой между процессором и памятью (на самом деле, это часть процессора, но это всего лишь деталь реализации).
6.4 Другие файловые системы
6.4 Другие файловые системы Операционная система Windows NT обеспечивает поддержку различных файловых систем. Основной, обладающей полным спектром возможностей файловой системой является NTFS. Компания Microsoft утверждает, что в ныне устаревшую файловую систему FAT новые функции
ГЛABA 7 Управление памятью
ГЛABA 7 Управление памятью B этой главе вы узнаете, как реализована виртуальная память в Microsoft Windows и как осуществляется управление той частью виртуальной памяти, которая находится в физической. Мы также опишем внутреннюю структуру диспетчера памяти и его компоненты, в том
Исторически так сложилось, что ОС Unix обеспечивает четыре абстракции, связанные с файловыми системами: файлы, элементы каталогов (directory entry), индексы (inode) и точки монтирования (mount point).
Файловая система — это иерархическое хранилище данных определенной структуры. Файловые системы содержат файлы, каталоги и соответствующую управляющую информацию. Обычные операции, которые выполняются с файловыми системами, — это создание (create), удаление (delete) и монтирование (mount). В ОС Unix файловые системы монтируются на определенную точку монтирования в общей иерархии[67], которая называется пространством имен (namespace). Это позволяет все файловые системы сделать элементами одной древовидной структуры[68].
Файл (file) — это упорядоченный поток байтов. Первый байт соответствует началу файла, а последний байт — концу файла. Каждому файлу присваивается удобочитаемое имя, по которому файл идентифицируется как пользователями, так и системой. Обычные файловые операции— это чтение (read), запись (write), создание (create) и удаление (delete).
Файлы помещаются в каталогах (directory). Каталог — это аналог папки, которая обычно содержит связанные между собой файлы. Каталоги могут содержать подкаталоги. В этой связи каталоги могут быть вложены друг в друга и образуют пути (path). Каждый компонент пути называется элементом каталога (directory entry). Пример пути — "/home/wolfman/foo". Корневой каталог "/", каталоги home и wolfman, a также файл fоо — это элементы каталогов, которые называются dentry. В операционной системе Unix каталоги представляют собой обычные файлы, которые просто содержат список файлов каталога. Так как каталог по отношению к виртуальной файловой системе — это файл, то с каталогами можно выполнять те же операции, что и с файлами.
Unix-подобные операционные системы отличают концепцию файла от любой информации об этом файле (права доступа, размер, владелец, время создания и т.д.). Последняя информация иногда называется метаданнымм файла (file metadata), т.е. данные о данных, и хранится отдельно от файлов в специальных структурах, которые называются индексами (inode). Это сокращенное название от index node (индексный узел), хотя в наши дни термин "inode" используется значительно чаще.
Вся указанная информация, а также связанная с ней информация о самой файловой системе хранится в суперблоке (superblock). Суперблок — это структура данных, которая содержит информацию о файловой системе в целом. Иногда эти общие данные называются метаданными файловой системы. Метаданные файловой системы содержат информацию об индивидуальных файлах и о файловой системе в целом.
Традиционно файловые системы ОС Unix реализуют эти понятия как структуры данных, которые определенным образом расположены на физических дисках. Например, информация о файлах хранится в индексе, в отдельном блоке диска, каталоги являются файлами, информация по управлению файловой системой хранится централизованно в суперблоке и т.д. Подсистема VFS операционной системы Linux рассчитана на работу с файловыми системами, в которых поддерживаются аналогичные концепции. Не Unix-подобные файловые системы, такие как FAT или NTFS, также работают в ОС Linux, однако их программный код должен обеспечить наличие аналогичных концепций. Например, если файловая система не поддерживает отдельные индексы файлов, то код должен построить в оперативной памяти структуры данных таким образом, чтобы казалось, что такая поддержка работает. Если файловая система рассматривает каталоги как объекты специальных типов, для VFS каталоги должны представляться как обычные файлы. Часто код не файловых систем не в стиле Unix требует выполнять некоторую дополнительную обработку чтобы уложиться в парадигму Unix и требования VFS. Такие файловые системы также поддерживаются, и обычно качество не особенно страдает.
Выделение памяти
Выделение памяти Сначала следует определить место для размещения строки при вводе. Как было отмечено раньше, это значит, выделить память, достаточную для размещения любых строк, которые мы предполагаем читать. Не следует надеяться, что компьютер подсчитает длину
(3.21) Как ускорить работу с памятью?
(3.21) Как ускорить работу с памятью? Можно регулировать несколько значений реестра для ускорения работы подсистемы памяти W2k. Но будьте осторожны, так как неправильные значения могу привести к неработоспособности системы. Вы можете изменить некоторые значения реестра в
File-backed
Когда память «поддерживается» файлами, данные загружаются с диска. В большинстве случаев они загружаются по требованию, однако вы можете дать подсказки ядру, чтобы оно могло предварительно подгрузить память перед чтением. Это помогает сохранять скорость вашей программы, когда вы знаете, что у вас есть определённый паттерн доступа (в основном последовательный доступ). Чтобы избежать использования слишком большого количества RAM, вы также можете сообщить ядру, что вы не хотели бы больше держать определённые страницы в RAM, при этом не нужно освобождать всю область памяти целиком. Советы ядру даются вызовами madvise().
Когда системе не хватает физической памяти, ядро попытается перенести некоторые данные из RAM на диск. Если память является file-backed и shared, это довольно просто. Поскольку файл является источником данных, они просто удаляются из RAM, а затем, в следующий раз, когда их нужно будет прочитать, они будут загружены из файла.
Ядро также может решить удалить анонимную/частную память из RAM. В этом случае эти данные записываются в определенном месте на диске. Говорят, что эти данные были вытеснены — «swapped out». Затем оно работает так же, как и для файловой памяти: когда к ней требуется доступ, она считывается с диска и перезагружается в RAM.
Благодаря использованию виртуального адресного пространства, замена страниц в обе стороны полностью прозрачна для процесса. Кроме того, что есть ощутимые задержки, вызванные дисковым вводом-выводом.
Автоматическое управление памятью
Автоматическое управление памятью Ни один из рассмотренных подходов не является полностью удовлетворительным. Общее решение проблемы управления памятью предполагает серьезную работу на уровне реализации
18.6.5 Выделение оперативной памяти для VMware
18.6.5 Выделение оперативной памяти для VMware Система VMware позволяет пользователям задавать как объем оперативной памяти, выделяемой каждому виртуальному компьютеру, так и общее количество ОП, зарезервированное для использования виртуальными машинами. Правильная настройка
3.2. Выделение памяти
3.2. Выделение памяти Четыре библиотечные функции образуют основу управления динамической памятью С Мы опишем сначала их, затем последуют описания двух системных вызовов, поверх которых построены эти библиотечные функции. Библиотечные функции С, в свою очередь, обычно
ГЛАВА 9. АЛГОРИТМЫ УПРАВЛЕНИЯ ПАМЯТЬЮ
ГЛАВА 9. АЛГОРИТМЫ УПРАВЛЕНИЯ ПАМЯТЬЮ Алгоритм планирования использования процессорного времени, рассмотренный в предыдущей главе, в сильной степени зависит от выбранной стратегии управления памятью. Процесс может выполняться, если он хотя бы частично присутствует в
5.1.3. Выделение сегментов памяти
5.1.3. Выделение сегментов памяти Процесс выделяет сегмент памяти с помощью функции shmget(). Первым аргументом функции является целочисленный ключ, идентифицирующий создаваемый сегмент. Если несвязанные процессы хотят получить доступ к одному и тому же сегменту, они должны
Политика и принципы управления проектом
Политика и принципы управления проектом Политика и принципы управления проектом должны быть окончательно определены и донесены до всех участников проекта как можно раньше.Стратегия проектаКак уже упоминалось в разделе «Информация как новый ресурс» в главе 1, внедрение
5.1. Различные файловые системы
5.1. Различные файловые системы Linux поддерживает много различных файловых систем. Начинающий пользователь просто теряется, когда видит такое многообразие выбора, — ведь в качестве корневой файловой системы доступны: ext2, ext3, ext4, XFS, ReiserFS, JFS.«Родной» файловой системой Linux
6.3. Некорректное обращение к памяти - page fault
Когда процесс делает что-то, что не нравится блоку управления памятью, выдается прерывание некорректного обращения к памяти - page fault. К этому могут привести следующие ситуации (список не полный):
- Чтение или запись в область памяти, которая не отображена в физическую память (флаг записи страницы / 'присутствия' таблиц не установлен)
- Процесс находится в пользовательском режиме и пытается записать в страницу, доступную только для чтения страницы.
- Процесс находится в пользовательском режиме и пытается получить доступ к странице, доступной только в режиме ядра.
- Запись страницы, находящаяся в таблице, повреждена - были перезаписаны зарезервированные биты.
Прерывание некорректного обращения к памяти имеет номер 14, и, если обратиться к главе 3, мы видим, что вырабатывается код ошибки. Эта ошибка дает нам довольно много информации о том, что произошло.
Бит 0 - Если установлен, то проблема возникла не из-за того, что страница не присутствовала в физической памяти. Если не установлен, то страница не присутствует в физической памяти.
Бит 1 - Если установлен, то это значит, что операция, из-за которой возникла проблема, была операцией записи, в противном случае это была операция чтения.
Бит 2 - Если установлен, то прерывание произошло, когда процессор работал в пользовательском режиме. В противном случае он работал в режиме ядра.
Бит 3 - Если установлен, то это означает, что проблема была вызвана тем, что были перезаписаны зарезервированные биты.
Бит 4 -Если установлен, то это значит, что проблема возникла в момент выборки команд.
Полезные утилиты
Утилиты как правило не входят в стандартные дистрибутивы ОС и устанавливаются отдельно.
Файловые системы
Файловые системы Таблица разделов указывает на первые сектора каждого раздела. Для размещения файлов в разделе его следует отформатировать, то есть создать внутри раздела файловую систему. Основная запись файловой системы обычно начинается в первом секторе раздела.
Управление памятью процесса
Управление памятью процесса Можно сказать, что каждый процесс в операционной системе UNIX выполняется на собственной виртуальной вычислительной машине, где все ресурсы принадлежат исключительно данному процессу. Подсистема управления памятью обеспечивает такую
Выделение
Выделение В главе 1, где говорится о Microsoft Windows, мы уже знакомились с понятием выделения. Однако это понятие настолько фундаментально, что мы возвращаемся к нему снова и будем возвращаться еще не раз. В этой главе мы обсудим два вида выделения: выделение текста и выделение
Одной из основных функций операционной системы является эффективное управление памятью. Оперативная память, или основная память, или память с произвольным доступом (Random Access Memory, RAM) является достаточно дорогостоящим ресурсом. Время доступа к оперативной памяти составляет всего несколько циклов процессора, поэтому работа с данными, находящимся в памяти, обеспечивает максимальную производительность. К сожалению, данный ресурс, как правило, ограничен. В большей степени это справедливо для многозадачной операционной системы общего назначения, каковой является UNIX. Поэтому данные, которые не могут быть размещены в оперативной памяти, располагаются на вторичных устройствах хранения, или во вторичной памяти, роль которой обычно выполняют дисковые накопители. Время доступа ко вторичной памяти па несколько порядков превышает время доступа к оперативной памяти и требует активного содействия операционной системы. Подсистема управления памятью UNIX отвечает за справедливое и эффективное распределение разделяемого ресурса оперативной памяти между процессами и за обмен данными между оперативной и вторичной памятью. Часть операций производится аппаратно устройством управления памятью (Memory Management Unit, MMU) процессора под управлением операционной системы, чем достигается требуемое быстродействие.
Примитивное управление памятью значительно уменьшает функциональность операционной системы. Такие системы, как правило, позволяют загрузить в заранее определенное место в оперативной памяти единственную задачу и передать ей управление. При этом задача получает в свое распоряжение все ресурсы компьютера (разделяя их, разумеется, с операционной системой), а адреса, используемые задачей, являются физическими адресами оперативной памяти. Такой способ запуска и выполнения одной программы безусловно является наиболее быстрым и включает минимальные накладные расходы.
Этот подход часто используется в специализированных микропроцессорных системах, однако практически неприменим в операционных системах общего назначения, какой является UNIX. Можно сформулировать ряд возможностей, которые должна обеспечивать подсистема управления памятью современной многозадачной операционной системы:
? Выполнение задач, размер которых превышает размер оперативной памяти.
? Выполнение частично загруженных в память задач для минимизации времени их запуска.
? Размещение нескольких задач в памяти одновременно для повышения эффективности использования процессора.
? Размещение задачи в произвольном месте оперативной памяти.
? Размещение задачи в нескольких различных частях оперативной памяти.
? Совместное использование несколькими задачами одних и тех же областей памяти. Например, несколько процессов, выполняющих одну и ту же программу, могут совместно использовать сегмент кода.
Все эти возможности реализованы в современных версиях UNIX с помощью т.н. виртуальной памяти, о которой пойдет речь в следующем подразделе. Виртуальная память не является "бесплатным приложением", повышая накладные расходы операционной системы: структуры данных управления памятью размещаются в оперативной памяти, уменьшая ее размер; управление виртуальной памятью процесса может требовать ресурсоемких операций ввода/вывода; для системы со средней загрузкой около 7% процессорного времени приходится на подсистему управления памятью. Поэтому от эффективности реализации и работы этой подсистемы во многом зависит производительность операционной системы в целом.
Данный текст является ознакомительным фрагментом.
Продолжение на ЛитРес
2.4. Файловые системы
2.4. Файловые системы Все современные дисковые операционные системы обеспечивают создание файловой системы, предназначенной для хранения данных на дисках и обеспечения доступа к ним. Принцип организации файловой системы – табличный. Поверхность жесткого диска
Обзор методов управления памятью
Обзор методов управления памятью Обо всех деталях отображения виртуальных адресов на физические адреса (virtual to physical memory mapping), механизмах страничной подкачки (page swapping) и замещения страниц по запросу (demand paging) и прочих моментах заботится ОС. Эти вопросы подробно обсуждаются
Выделение памяти, связанной с определенным процессором
Выделение памяти, связанной с определенным процессором В современных операционных системах широко используются данные, связанные с определенными процессорами (per-CPU data). Это данные, которые являются уникальными для каждого процессора. Данные, связанные с процессорами,
6.1. Виртуальная память (теория)
Если вы знаете, что такое виртуальная память, вы можете пропустить этот раздел.
Если в linux вы создадите крошечную программу, например,
, откомпилируете ее, а затем запустите 'objdump -f', вы можете увидеть нечто, похожее на следующее:
Обратите внимание на начальный адрес программы 0x80482a0, что эквивалентно приблизительно 128 Мб в адресном пространстве. Может показаться странным, но эта программа будет работать отлично на машинах с объемом оперативной памяти, меньшем 128 Мб.
То, что программа на самом деле «видит», когда она читает из памяти и пишет в память, является виртуальным адресным пространством. Часть виртуального адресного пространства отображается в физическую память, а часть - не отображается. Если вы пытаетесь получить доступ к неотображаемой части, то процессор выдаст сигнал о некорректном обращении к памяти page fault, операционная система ловит его, и в POSIX-системе выдает сигнал SIGSEGV, за которым непосредственно следует сигнал SIGKILL.
Эта абстракция является чрезвычайно полезной. Это означает, что с помощью компиляторов можно создавать программы, которые будут, когда запускаются, размещать код в конкретном месте в памяти. При использовании виртуальной памяти процесс считает, что он, например, находится по адресу 0x080482a0, но на самом деле это может быть место в физической памяти с адресом 0x1000000. В результате процессы не могут случайно (или намеренно) испортить данные других процессов.
Виртуальная память этого типа полностью зависит от поддержки аппаратным обеспечением. Ее нельзя эмулировать программно. К счастью, в архитектуре x86 есть именно такая возможность. Этот модуль называется MMU (Memory Management Unit- Устройство управление памятью) и он обрабатывает все операции по отображению памяти, связанные с сегментацией и страничной организацией памяти, образуя слой между процессором и памятью (на самом деле, это часть процессора, но это всего лишь деталь реализации).
Инструмент Выделение
Инструмент Выделение Для выделения, перемещения в пространстве доски, изменения некоторых свойств объектов служит инструмент Выделение. Для выбора какого-либо объекта на странице необходимо сначала активизировать инструмент Выделение, в этом случае курсор приобретет
Ошибка 0x000000C2: неправильное выделение памяти
Ошибка 0x000000C2: неправильное выделение памяти Некорректное выделение памяти. Причина – некорректно работающий
6.6. Файловые системы
6.6. Файловые системы 6.6.1. Назначение и функционирование файловой системы В операционных системах файловая система относится к основным понятиям и определяется как общая система, которая устанавливает правила присвоения имен файлам, хранение, организацию и обработку
1.3. Файловые системы CD и DVD
1.3. Файловые системы CD и DVD Чтобы проигрыватель дисков или компьютерный привод мог правильно читать информацию на CD/DVD большинства форматов, на дисках создается файловая система, подобная создаваемой на жестких дисках компьютера. Файловая система представляет собой
16.6. Новые файловые системы
16.6. Новые файловые системы Файловая система ext2fs была создана по образу и подобию файловой системы UNIX (UNIX File System - UFS). Обе они (особенно UFS) создавались еще в те времена, когда диски и другие физические носители данных имели довольно маленький (по современным меркам) объем.
Anonymous
Анонимная память — это чисто оперативная память (RAM). Тем не менее, ядро фактически не будет отображать эту память на физический адрес, прежде чем он в него будет фактически выполнена запись. Как следствие, анонимная память не добавляет никакой нагрузки на ядро до её фактического использования. Это позволяет процессу «резервировать» большую часть памяти в адресном пространстве виртуальной памяти без использования RAM. Как следствие, ядро позволяет зарезервировать больше памяти, чем доступно. Такое поведение часто упоминается как over-commit (или overcommitment).
Содержание
Примитивы управления памятью (Memory Handling Primitives)
Примитивы управления памятью (Memory Handling Primitives) Чтобы получать типичный указатель на неинициализированный буфер памяти данного размера, определена следующая функция:template ‹class T›inline T* allocate(ptrdiff_t n, Т*); // n ›= 0Размер (в байтах) распределённого буфера - не меньше n*sizeof(T).Для
Файловые системы Windows
Файловые системы Windows Windows поддерживает на непосредственно подключенных устройствах файловые системы четырех типов, но только первый из них будет иметь для нас существенное значение на протяжении всей книги, поскольку именно полнофункциональная файловая система этого
Шаг 19 - Управление памятью. Продолжение 1.
Шаг 19 - Управление памятью. Продолжение 1. Бог: "Я стер всякую жизнь. Впочем, я ничего не уничтожил. Я просто воссоединил в Себе частицы Себя. У меня на планете было множество типов с безумными глазами, которые болтали насчет слияния со Мной. Вот они и слились." Кармоди: "Им это
Объединенные файловые системы
Объединенные файловые системы Взгляните повнимательнее на уже знакомый нам рисунок. Пространство имен путей в QNX/Neutrino.Обратите внимание, что ответственными за префикс «/» объявили себя как файловая система fs-qnx4, так и администратор процессов. Это нормально, и
6.4. Применяем все на практике
Мы почти готовы приступить к реализации. Однако, нам сначала потребуются несколько вспомогательных функций, наиболее важными из которых являются функции управления памятью.
6.4.1. Простое управление памятью с помощью команды выделения памяти malloc
Если вы знаете язык C++, вы, возможно, слышали о команде 'placement new' (выделить новую память). Это версия команды new, у которой есть параметр. Вместо вызова команды malloc, которая используется обычно, команда new создает объект по указанному адресу. Мы будем использовать очень похожую концепцию.
Когда ядро уже достаточно загружено, у нас будет активная и функционирующая память типа heap (куча). Однако, для работы с памятью типа куча, как правило, требуется наличие виртуальной памяти. Поэтому прежде, чем можно будет пользоваться памятью типа куча, нужно иметь простую альтернативу для выделения памяти.
Поскольку нам нужно выделять память при загрузке ядра довольно рано, можно предположить, что ничего, кроме команд kmalloc() и kfree() нам не потребуется. Это существенно все упрощает. У нас может быть просто указатель (адрес размещения) для некоторой свободной памяти, который мы передаем обратно в requestee, а затем увеличиваем. Таким образом:
Этого, на самом деле, будет достаточно. Тем не менее, у нас есть еще одно требование. Когда мы размещаем таблицы и директории страниц, они должны быть выровнены по границам страниц. Так что мы можем собрать следующее:
Теперь, к сожалению, у нас есть еще одно требование, и я не могу объяснить вам, почему это необходимо до тех пор, пока позже мы не рассмотрим его в наших руководствах. Оно возникает, когда мы клонируем директорий страниц (когда выполняем операцию fork()). В этот момент уже будет работать страничная организация памяти и kmalloc вернет виртуальный адрес. Но, нам также потребуется (поверьте мне, позже вы будете довольны тем, что мы так сделали) получить физический адрес выделенной памяти. На данный момент примите это на веру - в любом случае для этого потребуется уж не так много кода.
Великолепно. Это все, что нужно для простого управления памятью. В моем коде я, на самом деле, (в эстетических целях) переименовал kmalloc в kmalloc_int (для kmalloc_internal). Еще у меня есть несколько функций-обверток:
Я просто чувствую, этот интерфейс лучше, чем просто указывать 3 параметра при каждом выделении памяти из кучи в ядре! Эти определения должны быть в файлах kheap.h/kheap.c.
6.4.2. Необходимые определения
В файле paging.h должны находиться определения некоторых структур, которые сделают нашу жизнь проще.
Обратите внимание на элементы tablesPhysical и physicalAddr из page_table_t. Что они там делают?
Элемент physicalAddr на самом деле только для того случая, когда мы клонируем директории страниц (объясним позднее в наших руководствах). Запомните, что в этот момент новый директорий будет иметь адрес в виртуальной памяти, который не совпадает с адресом физической памяти. Нам понадобится физический адрес для того, чтобы сообщить его процессору в случае, если мы когда-либо захотим переключать директории.
Элемент tablesPhysical аналогичен. Он решает следующую проблему: Как получить доступ к таблицам страниц? Это сделать, как кажется, просто, но помните, что в директории страниц должны храниться физические адреса, а не виртуальные. А единственный способ, которым мы можем читать из памяти и записывать в память, является использование виртуальных адресов!
Одно из решений этой проблемы состоит в том, чтобы никогда не получать доступ непосредственно к таблицам страниц, а отображать некоторую таблицу страниц обратно в директорий страниц так, что когда осуществляется доступ к памяти по определенному адресу, вы сможете увидеть все ваши таблицы страниц, как если бы они было просто страницами, и все записи в таблицах страниц, как если бы они были обычными числами. Этот способ, на мой взгляд, не совсем интуитивно понятен и для него потребуется еще 256 MB адресного пространства, поэтому я предпочитаю другой способ.
Второй способ заключается в том, для каждого директория страниц имеется 2 массива. В одном хранятся физические адреса его таблицы со страницами (для передачи их в процессор), а в другом хранятся виртуальные адреса (так что мы может их читать и делать в них запись). В результате у нас будет только 4KB дополнительных накладных расходов для каждого директория страниц, что не так много.
6.4.3. Размещение фреймов физической памяти
Если мы хотим отобразить страницу во фрейм, нам нужно каким-то образом найти свободный кадр. Конечно, мы могли бы просто поддерживать огромный массив из единиц и нулей, но это было бы крайне расточительно - нам не нужны 32-бит просто для того, чтобы хранить два значения. Поэтому если мы будем использовать набор битов bitset , то мы потратим памяти в 32 раза меньше!
Надеюсь, что код не должен вызвать слишком много сюрпризов. Это просто упражнения по работе с битами. Затем мы переходим к функциям выделения и освобождения фреймов. Теперь, когда у нас есть эффективная реализация bitset, эти функции будут всего в несколько строк!
Обратите внимание, что макрос PANIC просто вызывает глобальную функцию, которая называется panic, с аргументами __FILE__ и __LINE__. Функция panic печатает их и переходит в бесконечный цикл, останавливая все исполнение.
6.4.4. Наконец-то код для страничной организации памяти
Хорошо, давайте проанализируем код. Прежде всего, функции - утилиты.
Функция switch_page_directory делает именно то, что говорит название (переключение директория страниц). Она берет директорий страниц и переключается на него. Она делает это при помощи перемещения в регистр CR3 адреса элемента номера tablesPhysical этого директория. Помните, что номер tablesPhysical указывает на массив физических адресов. После этого она сначала получает содержимое регистра CR0, затем выполняет операцию OR с битом PG (0x80000000), а затем перезаписывает значение регистра. В результате включается страничная организация памяти, а также осуществляется сброс кэша с директорием страниц.
Функция get_page возвращает указатель запись страницы для конкретного адреса. В функцию также можно передать параметр make. Если make равен 1 и таблица страницы, в которой должна находиться запись о запрашиваемой странице, еще не была создана, то она создается. В противном случае, функция просто вернет 0. Если таблица уже назначена, функция найдет запись о странице и вернет ее. Если ее нет (и make == 1), то будет предпринята попытка создать ее.
Наша функция kmalloc_ap ищет блок памяти, который выровнен по границе страницы, и запоминает место его физического расположения. Физическое расположение сохраняется в 'tablesPhysical' (после того, как несколько битов сообщат процессору, что страница присутствует, в нее можно делать запись и она доступна пользователю), а виртуальное месторасположение запоминается в 'tables'.
Функция initialise_paging, во-первых, создаст bitset для фреймов и с помощью команды memset заполняет его нулями. Затем она для директория страниц выделяет пространство (которое выровнено по краю страницы). После этого, она размещает фреймы так, что доступ к любой странице будет отображаться во фрейм с соответствующим линейным адресом, называемым идентичным отображением. Это сделано для небольшой части адресного пространства, так что код ядра может работать, как обычно. Она регистрирует обработчик прерывания для неверного обращения к странице (смотрите ниже), а затем включает страничную организацию памяти.
6.4.5. Обработчик неверного обращения к странице
6.4.6. Тестирование
Отлично! Теперь у вас есть код, который позволяет включать страничную организацию памяти и обрабатывать неверное обращение к странице! Давайте просто проверим, как это на самом деле работает, не так ли .
Сейчас рассмотрим, как же работает с памятью ОС семейства UNIX.
Проблема управления памятью в ОО-модели
Проблема управления памятью в ОО-модели Подводя итог предшествующего анализа, определим оригиналы и соответственно достижимые объекты:Определение: начальные, достижимые и недостижимые объектыВ каждый момент времени выполнения системы множество оригиналов
Резидентная память
Всё, что мы рассматривали выше, относилось к виртуальной памяти. Речь шла о резервировании адресов памяти, но зарезервированный адрес не всегда сразу отображается в физическую память ядром. В большинстве случаев ядро откладывает фактическое распределение физической памяти до момента первого доступа (или время первой записи в некоторых случаях). и даже тогда это делается с детализацией до страницы (обычно 4 KiB). Более того, некоторые страницы могут быть вытеснены после выделения, это означает, что они записываются на диск, чтобы другие страницы могли быть помещены в RAM.
Как следствие, узнать фактический размер физической памяти, используемой процессом (так называемая резидентная память процесса) действительно непросто. и единственным компонентом системы, который на самом деле знает об этом, является ядро (это его работа). К счастью, ядро предоставляет некоторые интерфейсы, которые позволят вам получить некоторую статистику о системе или конкретном процессе.
При обсуждении формата исполняемых файлов и образа программы в памяти мы отметили, что сегменты данных и стека могут изменять свои размеры. Если для стека операцию выделения памяти операционная система производит автоматически, то приложение имеет возможность управлять ростом сегмента данных, выделяя дополнительную память из хипа (heap — куча). Рассмотрим этот программный интерфейс.
Память, которая используется сегментами данных и стека, может быть выделена несколькими различными способами как во время создания процесса, так и динамически во время его выполнения. Существует четыре способа выделения памяти:
1. Переменная объявлена как глобальная, и ей присвоено начальное значение в исходном тексте программы, например:
char ptype = "Unknown file type";
Строка ptype размещается в сегменте инициализированных данных исполняемого файла, и для нее выделяется соответствующая память при создании процесса.
2. Значение глобальной переменной неизвестно на этапе компиляции, например:
В этом случае место в исполняемом файле для ptype не резервируется, но при создании процесса для данной переменной выделяется необходимое количество памяти, заполненной нулями, в сегменте BSS.
3. Переменные автоматического класса хранения, используемые в функциях программы, используют стек. Память для них выделяется при вызове функции и освобождается при возврате. Например:
static int с = 4;
В данном примере переменные а и b размещаются в сегменте стека. Переменная с размешается в сегменте инициализированных данных и загружается из исполняемого файла либо во время создания процесса, либо в процессе загрузки страниц по требованию. Более подробно страничный механизм описан в главе 3.
4. Выделение памяти явно запрашивается некоторыми системными вызовами или библиотечными функциями. Например, функция malloc(3C) запрашивает выделение дополнительной памяти, которая в дальнейшем используется для динамического размещения данных. Функция ctime(3C), предоставляющая системное время в удобном формате, также требует выделения памяти для размещения строки, содержащей значения текущего времени, указатель на которую возвращается программе.
Напомним, что дополнительная память выделяется из хипа (heap) — области виртуальной памяти, расположенной рядом с сегментом данных, размер которой меняется для удовлетворения запросов на размещение. Следующий за сегментом данных адрес называется разделительным или брейк-адресом (break address). Изменение размера сегмента данных по существу заключается в изменении брейк-адреса. Для изменения его значения UNIX предоставляет процессу два системных вызова — brk(2) и sbrk(2).
int brk(void *endds);
void *sbrk(int incr);
Системный вызов brk(2) позволяет установить значение брейк-адреса равным endds и, в зависимости от его значения, выделяет или освобождает память (рис. 2.11). Функция sbrk(2) изменяет значение брейк-адреса на величину incr. Если значение incr больше 0, происходит выделение памяти, в противном случае, память освобождается.[23]
Рис 2.11. Динамическое выделение памяти с помощью brk(2)
Существуют четыре стандартные библиотечные функции, предназначенные для динамического выделения/освобождения памяти.
void *malloc(size_t size);
void *calloc(size_t nelem, size_t elsize);
void *realloc(void *ptr, size_t size);
void free(void *ptr);
Функция malloc(3C) выделяет указанное аргументом size число байтов.
Функция calloc(3C) выделяет память для указанного аргументом nelem числа объектов, размер которых elsize. Выделенная память инициализируется нулями.
Функция realloc(3C) изменяет размер предварительно выделенной области памяти (увеличивает или уменьшает, в зависимости от знака аргумента size). Увеличение размера может привести к перемещению всей области в другое место виртуальной памяти, где имеется необходимое свободное непрерывное виртуальное адресное пространство.
Функция free(3C) освобождает память, предварительно выделенную с помощью функций malloc(3C), calloc(3C) или realloc(3C), указатель на которую передается через аргумент ptr.
Указатель, возвращаемый функциями malloc(3C), calloc(3C) и realloc(3C), соответствующим образом выровнен, таким образом выделенная память пригодна для хранения объектов любых типов. Например, если наиболее жестким требованием по выравниванию в системе является размещение переменных типа double по адресам, кратным 8, то это требование будет распространено на все указатели, возвращаемыми этими функциями.
Упомянутые библиотечные функции обычно используют системные вызовы sbrk(2) или brk(2). Хотя эти системные вызовы позволяют как выделять, так и освобождать память, в случае библиотечных функций память реально не освобождается, даже при вызове free(3C). Правда, с помощью функций malloc(3C), calloc(3C) или realloc(3C) можно снова выделить и использовать эту память и снова освободить ее, но она не передается обратно ядру, а остается в пуле malloc(3C).
Для иллюстрации этого положения приведем небольшую программу, выделяющую и освобождающую память с помощью функций malloc(3C) и free(3C), соответственно. Контроль действительного значения брейк-адреса осуществляется с помощью системного вызова sbrk(2):
/* Определим текущий брейк-адрес */
printf("Текущий брейк-адрес= 0x%x ", obrk);
/* Выделим 64 байта из хипа */
/* Определим новый брейк-адрес */
printf("Новый адрес области malloc= 0x%x,"
" брейк-адрес= 0х%x (увеличение на %d байтов) ",
naddr, nbrk, nbrk — obrk);
/* "Освободим" выделенную память и проверим, что произошло
printf("Новый брейк-адрес= 0x%x (увеличение на %d байтов) ",
obrk, obrk — nbrk);
Откомпилируем и запустим программу:
$ a.out
Текущий брейк-адрес= 0x20ac0
Новый адрес области malloc = 0x20ac8, брейк-адрес = 0x22ac0
(увеличение на 8192 байтов)
Новый брейк-адрес = 0x22ac0 (увеличение на 0 байтов)
Как видно из вывода программы, несмотря на освобождение памяти функцией free(3C), значение брейк-адреса не изменилось. Также можно заметить, что функция malloc(3C) выделяет больше памяти, чем требуется. Дополнительная память выделяется для необходимого выравнивания и для хранения внутренних данных malloc(3C), таких как размер области, указатель на следующую область и т.п.
Данный текст является ознакомительным фрагментом.
Продолжение на ЛитРес
ГЛABA 12 Файловые системы
ГЛABA 12 Файловые системы B начале этой главы мы даем обзор файловых систем, поддерживаемых Windows, а также описываем типы драйверов файловых систем и принципы их работы, в том числе способы взаимодействия с другими компонентами операционной системы, например с диспетчерами
Архитектура системы управления памятью в Win32 и Win64
Архитектура системы управления памятью в Win32 и Win64 Win32 (в данном случае различия между Win32 и Win64 становятся существенными) — это API 32-разрядных ОС семейства Windows. "32-разрядность" проявляет себя при адресации памяти тем, что указатели (LPSTR, LPDWORD и так далее) являются 4-байтовыми
top, htop, ps.
Стандартные утилиты для мониторинга работающих процессов. Для каждого процесса выводят показатели: VIRT, RES, SHR.
В smem есть одна уникальная вещь, которая отличает его от традиционных инструментов мониторинга памяти. Дело в том, что smem сообщает вам PSS (Proportional Set Size), то есть он дает более полноценное представление о распределении памяти между приложениями и библиотеками в настройках виртуальной памяти.
Инструмент выводит карту адресного пространства процесса.
Системные вызовы
Их много, но основной — mmap.
6.2. Страничная организация памяти как конкретная реализация виртуальной памяти
Виртуальная память представляет собой принцип абстракции. Как таковой, он требует конкретизации с помощью некоторых систем/алгоритмов. Как сегментацию памяти (смотрите главу 3), так и страничную организацию памяти можно использовать как способ реализации виртуальной памяти. Однако, как уже упоминалось в главе 3, сегментация становится устаревшим способом. Страничная организация памяти является новой, лучшей альтернативой для архитектуры x86.
Страничная организация представляет собой разделение виртуального адресного пространства.
6.2.1. Запись, описывающая страницу
В каждом процессе обычно имеются различные наборы отображения страниц, так что пространства виртуальной памяти не зависят друг от друга. В архитектуре x86 (32-разрядной) размеры страниц зафиксированы в 4 Кб по размеру. У каждой страницы есть соответствующее слово дескриптора, которое сообщает процессору, какому кадру страница сопоставляется. Обратите внимание, что страницы и кадры должны быть выровнены по границе в 4Кб (4KB будет 0x1000 байтов), при этом младшие 12 битов 32-разрядного слова всегда равны нулю. Это используется архитектурой для хранения в них информации о странице, например, присутствует ли она в памяти в режиме ядра или в пользовательском режиме и т.д. Формат этого слова изображен на рисунке.
Поля этого слова довольно просты, так что давайте быстрее пробежимся по ним.
P - Установлено, если страница находится в памяти.
R/W - Если установлено, то на страницу можно выполнять запись. Если не установлено, то страница доступна только для чтения. Это поле не используется, когда код работает в режиме ядра (если не установлен флаг CR0).
U/S - Если установлено, то это пользовательский режим. В противном случае, это страница в режиме супервизора (ядра). Код пользовательского режима не может выполнять запись на страницы, находящиеся в режиме ядра, или читать из них.
Reserved - Для внутреннего использования процессором и это поле не следует менять.
A - Установлено, если к странице был доступ (выполнялось обращение процессора).
D - Установлено, если на станице выполнялась запись (страница изменена).
AVAIL - Эти три бита не используются и доступны в режиме ядра.
Page frame address - старшие 20 битов адреса фрейма в физической памяти.
6.2.2. Директории / таблицы страниц
Возможно, вы подсчитали на калькуляторе и выяснили, что чтобы создать таблицу, отображающую каждую страницу размером 4KB одним 32-битный дескриптором, для 4 ГБ адресного пространства потребуется 4 Мбайт оперативной памяти. Так или иначе, но это правда.
4 Мб могут показаться большими накладными расходами, и надо быть справедливым, так оно и есть. Если у вас есть 4 ГБ физической памяти, то это не много. Однако, если вы работаете на компьютере, у которого 16 МБ оперативной памяти, вы сразу потеряли четверть доступной памяти! Нам нужно что-нибудь получше, что будет занимать объем, пропорциональный объему имеющейся у вас оперативной памяти.
Да, у нас нет этого. Но в Intel придумали что-то похожее - они используют 2-х уровневую систему. Процессор получает информацию из директория страниц, большой таблицы размером в 4KB, каждая запись которой указывает на таблицу страниц. Таблица страниц опять же имеет размер в 4KB и каждая запись является записью таблицы страниц, приведенной выше.
Таким образом, все адресное пространство в 4 ГБ перекрыто таким образом, что если в таблице страниц нет записей, то ее можно очистить и в директории страниц можно сбросить флаг ее присутствия.
6.2.3. Подключение страничной организации памяти
Подключить страничную организацию памяти исключительно просто.
- Скопируйте место вашего директория страниц в регистр CR3. Это должен быть, конечно, физический адрес.
- Установите бит PG в регистре CR0. Вы можете сделать это с помощью операции OR и операнда 0x80000000.
7.5.1. Файловые системы
7.5.1. Файловые системы Файл /proc/filesystems хранит информацию об известных ядру типах файловых систем. Этот список не очень полезен, так как он не полный: файловые системы могут подключаться и отключаться динамически в виде модулей ядра. В файле /proc/filesystems перечислены типы
2.2. Динамическое выделение памяти и указатели
2.2. Динамическое выделение памяти и указатели Прежде чем углубиться в объектно-ориентированную разработку, нам придется сделать небольшое отступление о работе с памятью в программе на С++. Мы не сможем написать сколько-нибудь сложную программу, не умея выделять память
16.7. Журналируемые файловые системы
16.7. Журналируемые файловые системы Основная цель, которая преследуется при создании журналируемых файловых систем, состоит в том, чтобы обеспечить быстрое восстановление системы после сбоев (например, после потери питания). Дело в том, что если произойдет такой сбой, то
6.5.2 Выделение области
6.5.2 Выделение области Ядро выделяет новую область (по алгоритму allocreg, Рисунок 6.18) во время выполнения системных функций fork, exec и shmget (получить разделяемую память). Ядро поддерживает таблицу областей, записям которой соответствуют точки входа либо в списке свободных
18.1.3. Управление памятью
18.1.3. Управление памятью Управление памятью осуществляется с помощью параметра mem: mem=Определяет объем памяти, установленной в компьютере.Например: mem=16384K или mem=16M.Иногда нужно указать объем ОЗУ, отличный от того, который имеется на самом деле. Например, у вас чипсет Intel 810 с
Статическое выделение памяти в стеке
Статическое выделение памяти в стеке В пространстве пользователя многие операции выделения памяти, в частности некоторые рассмотренные ранее примеры, могут быть выполнены с использованием стека, потому что априори известен размер выделяемой области памяти. В
Шаг 18 - Управление памятью.
Шаг 18 - Управление памятью. Больше нет возможности обходить эту тему. Это слишком важно. Долго не хотел браться за нее, но она сама взялась за меня.В управлении памятью одна из самых больших проблем (для меня) состоит в том,что у авторов книг по C++ в этом месте случается как бы
Читайте также: