Что такое разделяемая память (shared memory) в Linux?

«Что такое разделяемая память (shared memory) в Linux?» — вопрос из категории Linux, который задают на 23% собеседований Devops Инженер. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Разделяемая память (Shared Memory) — это один из самых быстрых механизмов межпроцессного взаимодействия (IPC) в Linux. Он позволяет нескольким независимым процессам получить доступ к одной и той же области оперативной памяти для чтения и записи данных. Это достигается за счет отображения одного физического сегмента памяти в виртуальное адресное пространство каждого из участвующих процессов.

Преимущества:

  • Скорость: Данные не копируются между процессами (как в pipes или message queues), а напрямую читаются/пишутся в общую область. Это критически важно для высокопроизводительных систем (СУБД, кэши вроде Redis/Memcached, научные вычисления).
  • Гибкость: Можно передавать данные любого типа и сложной структуры.

Недостатки и сложности:

  • Синхронизация: Поскольку процессы работают с одной областью памяти, необходимы механизмы синхронизации (например, семафоры SysV или POSIX, мьютексы в разделяемой памяти) для предотвращения состояний гонки (race conditions) и повреждения данных.
  • Управление жизненным циклом: Необходимо явно создавать, подключать и удалять сегменты разделяемой памяти.

Основные API:

  1. System V Shared Memory (shmget, shmat, shmdt): Классический, но несколько устаревший интерфейс.
  2. POSIX Shared Memory (shm_open, mmap): Более современный и гибкий подход, интегрирующийся с файловой системой (/dev/shm).

Практический пример на C с использованием SysV IPC и семафоров для синхронизации:

#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <stdio.h>
#include <string.h>

// Простая структура для общих данных
struct shared_data {
    int counter;
    char message[256];
};

int main() {
    key_t key = ftok("/tmp", 'R');
    // 1. Создаем сегмент разделяемой памяти
    int shmid = shmget(key, sizeof(struct shared_data), IPC_CREAT | 0666);
    // 2. Присоединяем сегмент к адресному пространству процесса
    struct shared_data *data = (struct shared_data*) shmat(shmid, NULL, 0);

    // 3. Работаем с данными (в реальности здесь нужна синхронизация!)
    data->counter++;
    strcpy(data->message, "Hello from Process A");
    printf("Counter: %d, Message: %sn", data->counter, data->message);

    // 4. Отсоединяем сегмент
    shmdt(data);
    // (В одном из процессов нужно будет вызвать shmctl(shmid, IPC_RMID, NULL) для удаления)
    return 0;
}

В современных системах часто используются более высокоуровневые абстракции, построенные поверх разделяемой памяти, такие как memory-mapped files с помощью mmap() или специализированные библиотеки.