Виртуальная память в Solaris
Объем виртуальной памяти состоит из объема оперативной памяти и объема пространства свопинга (swap space), потому что процессам, запущенным в системе, обычно требуется больше места, чем допускает размер оперативной памяти. Назначение подсистемы виртуальной памяти в ядре состоит в том, чтобы с точки зрения процесса память была непрерывна и всегда доступна, но в действительности выделенные для процесса страницы памяти могут в произвольном порядке распределяться в ОП или быть выгруженными на диск в пространство свопинга. Вся виртуальная память разбита на страницы объемом 4 или 8 Кб, для определения фактического размера страницы памяти используется программа /usr/bin/pagesize или функция getpagesize.
Потребители виртуальной памяти в Solaris - ядро, кэши файловой системы, тесно разделяемая память (intimately shared memory) и процессы. Тесно разделяемая память имеется только в Solaris и представляет собой область разделяемой памяти, которую нельзя выгружать на диск; она используется некоторыми программами (например, Oracle).
Виртуальная память построена на четырех принципах.
1. Каждый процесс получает отдельное виртуальное адресное пространство (virtual address space), т.е. процессу доступен определенный диапазон ячеек памяти. Максимальный размер этого диапазона памяти определяется длиной слова адреса и для 32-разрядной ОС составляет 4 Гб, т.к. длина адреса – 32 бита. Подсистема виртуальной памяти соотносит пользовательскую часть виртуального адресного пространства и реальные страницы физической памяти.
2. Адресные пространства нескольких процессов могут перекрываться незаметно для этих процессов, если они используют общий код. Подсистема виртуальной памяти незаметно для процессов отображает разделяемую часть памяти в одну область физической памяти так, что в физической памяти содержится всего один экземпляр разделяемого ресурса.
3. Подсистема виртуальной памяти выгружает наименее используемые страницы памяти на диск в случае недостатка физической памяти для всех процессов.
4. Подсистема виртуальной памяти запрещает процессу обращаться к ячейкам памяти из чужого адресного пространства - это делается на аппаратном уровне посредством механизма диспетчеризации.
Оценка необходимого размера оперативной памяти
Для оценки памяти, занимаемой каждым из процессов, можно использовать как команды top и ps, так и команду pmap, которая дает более подробное распределение памяти по типам:
# pmap -x 1
1: /sbin/init
Address Kbytes RSS Anon Locked Mode Mapped File
08046000 8 8 8 - rw--- [ stack ]
08050000 40 40 - - r-x-- init
0806A000 8 8 8 - rw--- init
0806C000 16 16 16 - rw--- [ heap ]
<…>
FEFF0000 4 4 4 - rwx-- [ anon ]
FEFF3000 4 4 - - rwxs- [ anon ]
FEFFB000 8 8 8 - rwx-- ld.so.1
FEFFD000 4 4 4 - rwx-- ld.so.1
-------- ------- ------- ------- -------
total Kb 2528 1884 168 -
В Sоlaris существует семейство процессных утилит (proc tools), или p-команд, работающих с файловой системой /proc, в которую отображаются многие структуры ядра, например, таблица процессов. Они позволяют получать информацию о процессах, а некоторые из них могут проанализировать аварийно завершившийся процесс, если от него остался файл core. Файл core представляет собой дамп всех сегментов памяти процесса на момент аварийного завершения, поэтому его можно проанализировать так же, как и запущенный процесс. Он записывается в текущий каталог процесса в случае аварийного завершения и случаи прерывания процесса по сигналам KILL, TERM и HUP к этому не относятся.
Память потребляется не только процессами, но и кэшем файловой системы, тесно разделяемой памятью и ядром, но если в системе не запускается СУБД Oracle или подобное приложение, скорее всего, тесно разделяемая память не используется. Рекомендованным для Solaris 10 объемом памяти для компьютеров на базе х86 является 512 МБ, а минимальным (необходимым для ядра и обязательно запускающихся системных приложений) – 256 МБ. Для SPARC-систем эти значения уменьшаются в 2 раза, а размер области свопинга по умолчанию одинаков – 512 МБ.
Список свободных страниц (free list)
Список свободных страниц - это набор страниц, из которого они извлекаются по запросу процессов. Процессы берут память из него и возвращают ее обратно по завершении. Сканер страниц также возвращает память в список свободных страниц.
Каждый раз, когда процесс запрашивает память, происходит страничная ошибка (page fault), но на самом деле это не ошибка, а ситуация в системе управления виртуальной памятью, возникающая при обращении к странице памяти, отсутствующей в ОЗУ.
Страничные ошибки делятся на три типа:
Легкая страничная ошибка (minor page fault) - процесс попытался получить доступ к странице, изъятой сканером страниц, но еще не использованной повторно.
Значительная страничная ошибка (major page fault) - процесс пытается получить доступ к странице, изъятой сканером и уже отданной другому процессу.
Ошибка копирования при записи (copy-on-write fault) - процесс пытается записать данные в страницу памяти, используемую совместно с другими процессами.
После загрузки системы вся виртуальная память распределяется между процессами постранично. В ядре инициализируется таблица, в которой хранятся состояния страниц. Когда процесс запрашивает память, из списка свободных страниц извлекается страница, поступающая в распоряжение процесса. Такая схема называется выделением страниц по запросу (demand paging).
Если список свободных страниц уменьшается до размера lotsfree, ядро запускает сканер страниц. Он начинает искать страницы, которые можно выгрузить на диск, чтобы увеличить размер свободной памяти. Сканер страниц работает по двухстадийному алгоритму. Просматривая ОП в порядке возрастания адресов, он очищает бит MMU ("используемости") для каждой страницы, который устанавливается, когда идет обращение к странице. Сканер страниц ведет просмотр, но через некоторое время снова проверяет бит используемости уже просмотренных страниц, ожидая доступа к этим страницам и установки их битов используемости. Параметры slowscan и fastscan определяют время, которое пройдет между очисткой бита MMU и его повторной проверкой:
slowscan - первоначальная частота сканирования,
fastscan - частота сканирования в ситуации, когда свободной памяти не осталось.
Если при повторном просмотре бит MMU какой-то страницы остался в исходном состоянии, это означает, что к данной странице не обращались, и страницы, чей бит "используемости" не был изменен в течение определенного времени, выгружаются на диск, а освобожденная память пополняет список свободных страниц.
Ограничение использования оперативной памяти для отдельных проектов
Проектом в Solaris называется единица администрирования, предназначенная для управления ресурсами. К проекту могут относиться любые пользователи и группы, каждый пользователь или группа могут входить в несколько проектов.
Проект характеризуется уникальным идентификатором проекта (PROJID). Каждый пользователь обязательно относится к некоему проекту по умолчанию, и какой именно это проект, определяется при входе пользователя в систему. Пользователь обязательно имеет главный проект (по аналогии с главной группой), но может участвовать и в нескольких проектах.
Каждый процесс обязательно ассоциируется с проектом, но это не обязательно главный проект пользователя, запустившего процесс. Отнести пользователя или группу к проекту можно либо в описании пользователя в файле /etc/user_attr, либо в файле проектов /etc/project. В системе также имеется предопределенный проект default и к нему относятся все пользователи, группы и процессы, для которых явно не указано иное.
Алгоритм определения главного проекта:
если в файле /etc/user_attr запись об этом пользователе имеет атрибут project, то в качестве главного проекта пользователю назначается указанный проект;
если в /etc/project имется проект с именем user.UID, где UID совпадает с UID пользователя, то он назначается главным проектом пользователя;
если в /etc/project есть проект group.groupname и groupname совпадает с именем главной группы пользователя, то этот проект назначается главным пользователю;
если в базе проектов есть проект с именем default, то главным назначается он.
Если его определить не удалось, вход такому пользователю запрещается.
Файл /etc/project имеет такой формат:
projname:projid:comment:user-list:group-list:attributes, где
projname - уникальный идентификатор проекта, его имя;
projid - неотрицательное целое число (не большее 2147483647);
comment - описание проекта;
user-list - список пользователей, входящих в проект,
group-list - список групп, входящих в проект,
attributes - атрибуты проекта в формате имя=значение.
По умолчанию файл /etc/project выглядит так:
system:0::::
user.root:1::::
noproject:2::::
default:3::::
group.staff:10::::
Кроме редактирования вручную для изменения этого файла используются программы projadd, projmod и projdel. Получить информацию о соответствии процессов проектам можно с помощью ps, id, pgrep, prstat, например:
# ps -o user,pid,uid,projid
USER PID UID PROJID
root 729 0 1
root 735 0 1
# id
uid=0(root)
gid=0(root) groups=0(root),1(other),2(bin),3(sys),4(adm),5(uucp),6(mail),7(tty),8(lp),9(nuucp),12(daemon)
Синтаксис вызова pgrep:
pgrep -J projidlist,
например:
Приоритеты процессов, настройка таблиц диспетчера
Настройка таблиц диспетчера памяти производится в три этапа:
вывод существующей таблицы в текстовый файл;
редактирование этого файла;
загрузка новой таблицы диспетчера в ядро.
Вначале выводится текущая таблица приоритетов в файл:
dispadmin -c TS -g > priority
# Time Sharing Dispatcher Configuration
RES=1000
# ts_quantum ts_tqexp ts_slpret ts_maxwait ts_lwait PRIORITY LEVEL
160 6 51 0 51 # 16
160 7 51 0 51 # 17
160 8 51 0 51 # 18
<…>
Затем она редактируется в текстовом редакторе и загружается в ядро:
dispadmin -c TS -s priority
Процессы, приоритет которых не изменился, можно просмотреть командой
ps -ecL | grep
, остановить и перезапустить.
Но можно регулировать приоритет процесса напрямую с помощью команды priocntl:
#priocntl -s -c TS -p -10
Приоритет всех процессов в классе разделения времени понижен на 10.
Ключ -s означает требование установить приоритет, а -p позволяет задать относительное изменение приоритета. Для указания конкретного признака процесса (например, идентификатора) следует использовать ключ -i :
priocntl -s -c TS -p -30 -i pid 22
Понижен приоритет процесса с PID=22.
Для вывода списка части процессов вместе с заголовком используется POSIX-совместимая программа grep:
# /usr/bin/ps -ecL | /usr/xpg4/bin/grep -E 'nscd|PID'
PID LWP CLS PRI TTY LTIME CMD
325 1 TS 59 ? 0:00 nscd
325 2 TS 59 ? 0:00 nscd
325 3 TS 59 ? 0:00 nscd
325 4 TS 59 ? 0:00 nscd
325 5 TS 59 ? 0:00 nscd
<…>
Эффективное использование памяти и свопинга
Если цена важнее производительности, то при нехватке памяти увеличивают размер раздела свопинга, если важнее производительность - увеличивают объем ОП, потому что при нехватке виртуальной памяти новые процессы не смогут быть запущены (будут выводиться сообщения"Not enough space" или “File system full, swap space limit exceeded").
Если виртуальной памяти достаточно, но оперативной памяти не хватает, система будет в значительной степени занята пейджингом и не сможет нормально откликаться на запросы, что увеличит дисковую активность (обращения к дискам с целью чтения или записи данных) и процент занятого сканером страниц процессорного времени.
Частота сканирования страниц
Повышенная частота сканирования страниц (scan rate) - главный показатель недостатка оперативной памяти. Для просмотра значения scan rate используются команды sar –g или
# vmstat
kthr memory page disk faults cpu
r b w swap free re mf pi po fr de sr cd f0 s0 -- in sy cs us sy id
1 0 0 704876 301492 242 1247 0 0 7 0 1223 43 2 -0 0 805 9355 2982 16 26 59
При анализе частоты сканирования с помощью vmstat можно запустить эту программу с параметром n для получения статистики каждые n секунд – например, vmstat 60.
Первую строку - суммарную статистику - можно игнорировать. Если показатель page/sr остается выше 200 страниц в секунду в течение длительного времени, это говорит о вероятной нехватке оперативной памяти в системе. Но высокое значение также может быть вызвано активностью процесса (или нескольких процессов одновременно), читающего данные с диска или получающего их через сеть - эти данные не только кэшируются операционной системой, но и занимают место в памяти, поэтому и могут вызвать активный пейджинг.
Активность свопинга
Если устройство, на котором находится область свопинга, загружено вводом-выводом, это говорит о нехватке памяти. Можно оценить дисковую активность устройства, на котором находится область свопинга, с помощью программы iostat:
# iostat -xPnce
cpu
us sy wt id
13 26 0 61
extended device statistics ---- errors ---
r/s w/s kr/s kw/s wait actv wsvc_t asvc_t %w %b s/w h/w trn tot dev
Она используется для получения информации об активности передачи данных в/из конкретных разделов дисков. Длинная очередь страниц для выгрузки свидетельствует о необходимости увеличения ОП.
Можно также использовать sar –d или vmstat.
Использование памяти процессами
Кроме pmap, информация о размере процесса в оперативной памяти также содержится в колонке RSS вывода программ top и ps:
# ps -ly
S UID PID PPID C PRI NI RSS SZ WCHAN TTY TIME CMD
S 0 623 620 0 67 20 2484 4716 ? pts/2 0:00 bash
O 0 642 623 0 40 20 1468 4056 pts/2 0:00 ps
Статистику использования разделяемой памяти можно просмотреть командой ipcs –mb.
Размер пространства свопинга
Для управления пространством свопинга используется программа swap. Получить информацию о текущем состоянии пространства свопинга можно с помощью swap –l:
# swap -l
swapfile dev swaplo blocks free
/dev/dsk/c3d0s1 102,1 8 1048568 1048568
Для выяснения общего объема виртуальной памяти, который включает в себя объем оперативной памяти и пространства свопинга вместе, следует использовать swap -s или sar -r.
# swap -s
total: 145604k bytes allocated + 12824k reserved = 158428k used, 536420k available
Параметры ядра и пейджинг
physmem: общее количество страниц в оперативной памяти.
lotsfree: когда размер свободной ОП становится меньше этого значения, сканер страниц начинает работать.
Значение по умолчанию - physmem/64, но может быть изменено в /etc/system. Сканер страниц по умолчанию запускается в режиме пейджинга, а не свопинга. Частота сканирования (scan rate, sr в выводе vmstat) устанавливается равной параметру slowscan, который по умолчанию равен fastscan/10.
minfree: пока объем свободной памяти находится между lotsfree и minfree, частота сканирования страниц растет линейно от slowscan к fastscan. Значение minfree по умолчанию - desfree/2, значение fastscan по умолчанию - physmem/4. Если свободной памяти становится меньше, чем desfree (что по умолчанию равно lotsfree/2), сканер страниц начинает запускаться с частотой 100 раз в секунду. За каждый запуск сканер страниц проверяет desscan страниц и этот параметр изменяется динамически вместе с частотой сканирования.
maxpgio: этот параметр по умолчанию ограничивает частоту ввода-вывода на устройство пейджинга. Можно установить значение maxpgio в сто раз больше количества жестких дисков, задействованных в свопинге.
throttlefree: когда свободной оперативной памяти становится меньше, чем определено в throttlefree (по умолчанию этот параметр равен minfree), запросы процессов на выделение новых страниц памяти переводятся в состояние ожидания, пока не появятся свободные страницы.
Алгоритм освобождения памяти, называемый cyclical page cache и применяющийся в Solaris начиная с 8-й версии, рассчитан на то, что при нехватке памяти выгружаются прежде всего страницы файлового кэша, и только затем - страницы процессов. Этот алгоритм используется для тех же целей, что и вышеописанный priority paging (с проверкой бита «используемости») в Solaris 7, но использует два списка свободных страниц: первый - для помещения в него освобождающихся страниц кэша, другой - для помещения прочих освобождающихся страниц (разделяемой памяти, процессов). Следовательно, файловый кэш не конкурирует ни с кем за место в памяти и в выводе vmstat он показывается как свободная память.
Для получения отдельного отчета по пейджингу страниц приложений (executables), данных (anonymous) и ФС используется
# vmstat -p
memory page executable anonymous filesystem
swap free re mf fr de sr epi epo epf api apo apf fpi fpo fpf
602212 155404 103 543 3 0 467 0 0 2 0 0 0 0 0 0
Свопинг
Если системе в течение некоторого времени не хватает памяти (объем свободной оперативной памяти падает ниже desfree), то начинается свопинг процессов. Планировщик задач выгружает те процессы, которые не претендовали на процессорное время в течение более чем maxslp секунд. По умолчанию maxslp равно 20. Этот режим свопинга называется мягким.
Если памяти меньше, чем desfree, и несколько процессов находятся в очереди к процессору, а активность пейджинга превышает maxpgio, начинается жесткий свопинг. Это означает, что ядро выгружает модули и страницы кэша, а затем начинает последовательно выгружать процессы до тех пор, пока объем свободной памяти не станет больше desfree.
Не выгружаются:
- процессы классов планирования SYS и RT;
- процессы, запускаемые в данный момент или остановленные по сигналу;
- процессы, завершающие работу;
- процессы-зомби;
- системные потоки;
- процессы, которые блокируют другие, более высокоприоритетные потоки.
Изменяемые параметры ядра
Основным параметром является maxusers, влияющий на значения параметров max_nprocs, maxuprc и др., раньше определявший максимальное разрешенное количество одновременно работающих в системе пользователей. Сейчас этот параметр просто устанавливает различные размеры таблиц ядра, учитывая максимальное количество пользователей. Параметры ядра, вычисляемые на основе maxusers: максимально допустимое количество процессов в системе, число структур квотирования и размер кэша имен каталогов (directory name lookup cache – DNLC).
По умолчанию значение maxusers равно меньшему из двух чисел – объему памяти системы в мегабайтах или 2048, при явном указании в /etc/system – от 1 до 4096. Если необходимо увеличить значение этого параметра, система будет выводить сообщения “out of processes”.
Параметр max_nprocs ограничивает максимальное количество процессов, одновременно запускаемых в системе, и влияет на вычисление значения maxuprc, размеров DNLC, резервирование структур для квотирования дискового пространства (если не указано явно значение ndquot), настройку подсистемы Hardware Address Translation, а также с помощью него проверяется соответствие размера памяти, занимаемой семафорами, системным ограничениям.
Значение max_nprocs по умолчанию – 10 + (16 x maxusers), диапазон значений – от 266 до максимально возможного идентификатора процесса (maxpid). Следовательно, изменение этого параметра требуется при одновременном запуске более 32000 процессов (maxusers=2048).
Ограничение на количество процессов, запускаемых одним пользователем, контролируется параметром maxuprc и по умолчанию этот параметр равен разности max_nprocs и reserved_procs, где reserved_procs – это параметр, отвечающий за резервирование идентификаторов процессов для root (по умолчанию равен 5). Параметр maxuprc можно только уменьшить.
При превышении ограничения, установленного параметром maxuprc, выводится сообщение "out of per-user processes for uid N".
Размер кэша имен каталогов определяется параметром ncsize, вычисляемым по формуле:
(4 x (v.v_proc + maxusers) + 320) + (4 x (v.v_proc + maxusers) + 320 / 100
В Solaris 10 значение по умолчанию вычислялось по другой формуле, что было ошибкой:
4 x (v.v_proc + maxusers) + 320 / 100
Параметр может изменяться от 0 до MAXINT.
Параметр ndquot определяет число структур квотирования в файловой системе UFS (если квотирование поддерживается):
(maxusers x 40) / 4) + max_nprocs
Если появляются сообщения “dquot table full”, параметр нужно изменить, интервал значений – тоже от 0 до MAXINT.