Публичный аккаунт 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_FAILEDaddr: указанный дескриптор 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
Друзья, которым понравилась эта статья, пожалуйста, нажмите и удерживайте изображение, чтобы подписаться на номер подписки Чжэн Эрдос, более интересный контент будет доставлен как можно скорее.