анализ разделяемой памяти nginx

Nginx

Публичный аккаунт WeChat:Чжэн Эрдос
Подпишитесь, чтобы узнать большеNginxзнание. Любые вопросы или предложения, пожалуйста, оставьте сообщение в публичном аккаунте;
Обратите внимание на официальный аккаунт, интересные и содержательные статьи будут доставлены в ближайшее время!

Общая память

Общая память — это самый простой метод межпроцессного взаимодействия в Linux. Он создает непрерывное линейное адресное пространство в памяти с помощью системных вызовов mmap или shmget, которые можно освободить с помощью системных вызовов munmap или shmdt. Преимущества использования разделяемой памяти: Когда несколько процессов используют один и тот же участок разделяемой памяти, если какой-либо процесс изменяет содержимое в разделяемой памяти, другие процессы могут получить измененное содержимое, обратившись к этой разделяемой памяти.

структура данных

Структура данных, используемая nginx, выглядит следующим образом:

1 typedef struct {
2    u_char      *addr;    /* 共享内存的起始地址 */
3    size_t       size;    /* 共享内存的长度 */
4    ngx_str_t    name;    /* 共享内存的名字  */
5    ngx_log_t   *log;     /* 记录日志的对象 */
6
7/* unsigned  exists:1;  */ /*共享内存是否已经分配过,1:已经分配 */
8    ngx_uint_t   exists;   
9} ngx_shm_t;

API общей памяти

nginxоперативная разделяемая памятьAPIИх два, а именно:

1ngx_int_t ngx_shm_alloc(ngx_shm_t *shm);    /* 分配新的共享内存 */
2void ngx_shm_free(ngx_shm_t *shm);    /*释放已经存在的共享内存 */

Метод реализации

вышеnginxДва операционных общей памяти вapi. Мы должны использовать два вышеупомянутыхapiРаботает с общей памятью.
Для портативности,nginxЕсть три способа достичь выше дваapi, три способа следующие:
1. Использовать без файлов сопоставленияmmapВыделить общую память
2, с/dev/zeroиспользование файлаmmapКарта общей памяти.
3. Используйтеshmgetвызов для выделения общей памяти

Анализ исходного кода

Исходный код очень прост, мыmmapПроведение простого анализа

 1#if (NGX_HAVE_MAP_ANON)
2
3ngx_int_t
4ngx_shm_alloc(ngx_shm_t *shm)
5{
6    /* MAP_ANON:不使用文件映射方式,因此fd,offset无用,相当于在内存开辟一块空间用于共享,由master创建 */
7    shm->addr = (u_char *) mmap(NULL, shm->size,
8                                PROT_READ|PROT_WRITE,
9                                MAP_ANON|MAP_SHARED, -1, 0);
10
11    if (shm->addr == MAP_FAILED) {
12        ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno,
13                      "mmap(MAP_ANON|MAP_SHARED, %uz) failed", shm->size);
14        return NGX_ERROR;
15    }
16
17    return NGX_OK;
18}
19
20
21void
22ngx_shm_free(ngx_shm_t *shm)
23{
24    if (munmap((void *) shm->addr, shm->size) == -1) {
25        ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno,
26                      "munmap(%p, %uz) failed", shm->addr, shm->size);
27    }
28}
29
30#elif (NGX_HAVE_MAP_DEVZERO)

можно увидетьngx_shm_allocиngx_shm_freeэто такmmapиmunmapупакован отдельно. и используетсяMAP_ANON, заключается в том, чтобы освободить место в памяти для общей памяти, а не для сопоставления файлов на жестком диске.

Как nginx использует разделяемую память

Во-первых, мы должны знать: по умолчанию, поforkПорожденный дочерний процесс не разделяет область памяти со своим родительским процессом. ноmasterиworkerПроцесс является родительско-дочерним процессом, что мне делать? как сделатьmasterпроцесс сworkerКак насчет общей памяти процесса?
Решениеmmapизflagsпараметр.masterВ процессе звонкаforkуказать доflagsзаMAP_SHAREDзвонитьmmap,В настоящее время,POSIXЭто делается для того, чтобы отношения отображения памяти в родительском процессе сохранялись в дочернем процессе, а изменения, внесенные родительским процессом в разделяемую память, могли быть видны дочернему процессу, и наоборот. Итак, поток:masterпроцесс в памяти сMAP_SHAREDспособ открыть часть общей памяти и сопоставить ее с областью общей памяти в адресном пространстве своего собственного процесса, а затемmasterперечислитьfork, дочерний процесс является производным, и дочерний процесс также унаследует эту общую область памяти в своем собственном адресном пространстве. Это решает проблему.

функции mmap/munmap

1void *mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset);

Возвращаемое значение: успех: начальный адрес отображаемой области; ошибка:MAP_FAILED
addr: указанный дескриптор fd должен быть сопоставлен с начальным адресом адресного пространства процесса, как правилоNULL, Это означает, что ядро ​​​​выберет свой собственный начальный адрес
len: Сопоставить количество байтов, сопоставленных на промежуточное пространство
prot: мы можем обрабатывать данные в этой общей памяти следующим образом:

prot инструкция
PROT_READ данные доступны для чтения
PROT_WRITE данные доступны для записи
PROT_EXEC Данные могут быть реализованы
PROT_NONE Данные недоступны

flags: Является ли поведение изменения данных в области разделяемой памяти общим или частным, т. е. видимым для всех процессов или только для этого процесса. следующее:

flags инструкция
MAP_SHARED Изменения доступны
MAP_PRIVATE Изменения являются частными
MAP_FIXED Точная интерпретация параметров ADDR

fd: Сопоставленный файловый дескриптор
offset: начальная позиция отображаемой области в файле.
Подробности смотрите на рисунке ниже:

映射区域
область карты

нужно знать, это:nginxОбщая память — это не то, что находится в отображаемом файле. когдаflagsпараметрMAP_ANONилиMAP_ANONYMOUS, что означает, что он не отображается из файла, а открывает только непрерывное линейное адресное пространство из памяти в качестве общей памяти. Поэтому в этом случаеfdиoffsetПараметры бессмысленны, устанавливайте их отдельно-1и0Вот и все.

Чтобы удалить отображение из адресного пространства процесса, вызовитеmunmap.

1int  munmap(void *addr, size_t len);

Успех: 0 Ошибка: -1


Друзья, которым понравилась эта статья, пожалуйста, нажмите и удерживайте изображение, чтобы подписаться на номер подписки Чжэн Эрдос, более интересный контент будет доставлен как можно скорее.

郑尔多斯
Чжэн Эрдос