Один из вопросов, которые задают системные администраторы Solaris, относится к статистике памяти, отображаемой утилитами типа prstat , особенно в окружении Oracle. Недоразумение вызывает показ десятков гигабайт используемой памяти в то время, как физически установленной памяти в системе меньше. Ответ кроется в основном в том, как считать использование памяти. В примере ниже часть shared memory выделена одному процессу и затем прикреплена к другим процессам, размер распределенной памяти - 100 МB.
Если
shared memory отображена только как часть процесса, выделившего ее, то сумма всей используемой памяти будет более точной. В нашем случае они все используют один и тот же сегмент размером 100 MB, но когда рассматриваются по отдельности, то каждый из них имеет в наличии 100 MB. Если сегмент
shared memory отображен как часть каждого процесса, 100 MB-вый разделенный сегмент будет подсчитан дважды, поскольку он хоть в действительности и один, но присоединен ко множеству процессов. Таким путем Solaris предпочитает отображать использование памяти.
Взглянем на более практический пример, ниже у нас две очень простые программы: одна для создания сегмента
shared memory (shm_creator), и вторая для присоединения к этому сегменту и отображения его в своем адресном пространстве:
shm_creator
/* Simple program to demonstrate SHM allocation
and its effect on the memory statistics
displayed by utilities like "prstat".
*/
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#define SHMSZ 104857600 /* 100MB */
#define true 1
main()
{
char c;
int shmid;
key_t key;
char *shm, *s;
/*
* We'll name our shared memory segment
* "123321".
*/
key = 123321;
/*
* Create the segment.
*/
if ((shmid = shmget(key, SHMSZ, IPC_CREAT | 0666)) < 0) {
perror("shmget");
exit(1);
}
/*
* Now we attach the segment to our data space.
*/
if ((shm = shmat(shmid, NULL, 0)) == (char *) -1) {
perror("shmat");
exit(1);
}
/*
* Now put some things into the memory for the
* other process to read.
*/
s = shm;
strcpy(s,"Hello From Server ....");
/*
* Now we just sleep forever sothat we have time
* to play with prstat etc.
*/
while (true) {
sleep(60);
}
*s = NULL;
exit(0);
}
shm_attach
/* Simple program to demonstrate SHM allocation
and its effect on the memory statistics
displayed by utilities like "prstat".
*/
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#define SHMSZ 104857600 /* 100MB */
#define true 1
main()
{
int shmid;
key_t key;
char *shm, *s;
/*
* We need to get the segment named
* "123321", created by the server.
*/
key = 123321;
/*
* Locate the segment.
*/
if ((shmid = shmget(key, SHMSZ, 0666)) < 0) {
perror("shmget");
exit(1);
}
/*
* Now we attach the segment to our data space.
*/
if ((shm = shmat(shmid, NULL, 0)) == (char *) -1) {
perror("shmat");
exit(1);
}
s = shm;
/*
* Sleep , print the string the server left
* for us in the shared memory segment, Sleep again
* do this forever .........
*/
while (true) {
printf("String from SHM : %s \n",s);
sleep (10);
}
*s = NULL;
exit(0);
}
Для того, чтобы отличать наши тестовые процессы от остальной статистики Solaris, мы создадим нового пользователя и
project для распределения этих процессов. Кто не знаком с
project, читайте
документацию.
# groupadd -g 2222 test
# projadd -U test -p 2222 testproj
# projmod -c 'Test Project for SHM' testproj
Для запуска программ мы будем использовать команду
newtask, которая позволит нам выполнять процессы в указанном проекте. Сначала запустим процесс сервера (shm_creator), который распределит сегмент shared memory.
# newtask -p testproj ./shm_creator
Если мы посмотрим на память, распределенную проектом с помощью
prstat, мы увидим, что используется около 100 MB:
# prstat -J

Теперь мы запускаем процесс, который присоединяется к этому сегменту памяти: помните, что процесс не распределяет еще дополнительно 100 MB памяти, он только присоединяется к тому же самому сегменту
shared memory, созданному первым процессом:
# newtask -p testproj ./shm_attach
String from SHM : Hello From Server ....
Из статистики
prstat теперь видно, что проект в общей сложности распределил 200 MB, но помните, что реальная распределенная память - 100 MB.
# prstat -J

Другие инструментальные средства, которые могут использоваться для изучения
shared memory, включают утилиты
ipcs и
pmap. Команда
ipcs используется, чтобы отобразить сегменты
shared memory, очереди сообщений и семафоры в Solaris. В наших целях мы будем использовать ее, чтобы взглянуть на сегмент
shared memory, который мы создали:
# ipcs -m -J -t -p -o
IPC status from as of Tue Mar 20 00:53:02 GMT+4 2007
T ID KEY MODE OWNER GROUP NATTCH CPID LPID ATIME DTIME CTIME PROJECT
Shared Memory:
m 26 0x1e1b9 --rw-rw-rw- root root 2 3063 3065 0:25:23 no-entry 0:16:18 testproj
Из вывода видно, что существуют два процесса, которые присоединены к этому сегменту (NATTCH) и что создатель сегмента принадлежит проекту
testproj. Второй инструмент, который мы будем использовать -
pmap, эта утилита показывает информацию об адресном пространстве для указанного процесса. В нашем случае мы будем использовать ее для наблюдения за процессом, который создал сегмент
shared memory и процессом, который присоединился к нему. Сначала посмотрим на процесс, который создал
shared memory-сегмент:
В выводе можно видеть сегмент 100 MB, идентифицированный пометкой
shmid=0x1a.
Если мы посмотрим на процесс, который присоединился к этому сегменту, то мы увидим тот же самый прикрепленный сегмент:
Это только два процесса, совместно использующие 100 МБ: если посмотреть на базу Oracle, картина покажется более искаженной, если не знать, как интерпретировать статистику.
Каждый процесс сервера Oracle разделяет сегменты памяти для базы данных. Так как эти общие сегменты памяти в Oracle нередко достигают нескольких гигабайт, становится понятно, почему
prstat может показывать большой объем используемой памяти.
Как последнее примечание, подобный случай существует и для
shared-библиотек, поскольку они обычно загружаются в системе только раз и отображаются ко всем процессам, которые используют ту же самую
shared-библиотеку. Поскольку они обычно намного меньше чем гигабайтовые сегменты распределенной памяти баз данных, то обычно остаются незамеченными.
Вольный перевод заметки Hein