Skip to content

Latest commit

 

History

History
 
 

mmap

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 

Страницы памяти в виртуальном адресном пространстве

Инструменты

Кроме пошагового отладчика gdb, при работе с памятью существуют дополнительные инструменты, предназначенные для выявления проблем.

Интерпретируемое выполнение с помощью valgrind

Набор инструментов valgrind использует контролируемое выполнение инструкций программы, модифицируя её код перед выполнением на физическом процессоре.

Основные инструменты:

  • memcheck - диагностика проблем с памятью: неверные указатели на кучу, повторное освобождение, чтение неинициализированных данных и забытое освобождение памяти.
  • callgrind - диагностика производительности выполняемой программы.

Для запуска программы под valgrind необходимо собрать программу с отладочной информацией (опция компиляции -g), в противном случае вывод valgrind будет не информативным.

Запуск:

> valgrind --tool=ИНСТРУМЕНТ program.jpg ARG1 ARG2 ... ARGn

В случае использования инструмента callgrind, после выполнения программы генерируется файл callgrind.out в формате XML, который можно визуализировать с помощью KCacheGrind (из KDE во всех современных дистрибутивах Linux), либо его кросс-платформенном аналоге QCacheGrind.

Runtime-проверки ошибок с помощью sanitizer'ов

Требует для своей работы свежие версии clang или gcc, и позволяют выполнять инструментальный контроль во время выполнения программы значительно быстрее, чем valgrind.

Реализуются на уровне генерации кода и замены некоторых функций, например malloc/free на реализации с дополнительными проверками.

Основные санитайзеры:

  • AddressSanitizer (-fsanitize=address) - диагностирует ситуации утечек памяти, двойного освобождения памяти, выхода за границу стека или кучи, и использования указателей на стек после завершения работы функции.
  • MemorySanitizer (-fsanitize=memory) - диагностика ситуаций чтения неинициализированных данных. Требует, чтобы программа, и как и все используемые ею библиотеки, были скомпилированы в позиционно-независимый код.
  • UndefinedBehaviourSanitizer (-fsanitize=undefined) - диагностика неопределенного поведения в целочисленной арифметике: битовые сдвиги, знаковое переполнение, и т.д.

Системный вызов mmap

#include <sys/mman.h>

void *mmap(
    void *addr,    /* рекомендуемый адрес отображения */
    size_t length, /* размер отображения */
    int prot,      /* аттрибуты доступа */
    int flags,     /* флаги совместного отображения */
    int fd,        /* файловый декскриптор фала */
    off_t offset   /* смещение относительно начала файла */
  );

int munmap(void *addr, size_t length) /* освободить отображение */

Системный вызов mmap предназначен для создания в виртуальном адресном пространстве процесса доступной области по определенному адресу. Эта область может быть как связана с определенным файлом (ранее открытым), так и располагаться в оперативной памяти. Второй способ использования обычно реализуется в функциях malloc/calloc.

Память можно выделять только постранично. Для большинства архитектур размер одной страницы равен 4Кб, хотя процессоры архитектуры x86_64 поддерживают страницы большего размера: 2Мб и 1Гб.

В общем случае, никогда нельзя полагаться на то, что размер страницы равен 4096 байт. Его можно узнать с помощью команды getconf или функции sysconf:

# Bash
> getconf PAGE_SIZE
4096

/* Си */
#include <unistd.h>
long page_size = sysconf(_SC_PAGE_SIZE);

Параметр offset (если используется файл) обязан быть кратным размеру страницы; параметр length - нет, но ядро системы округляет это значение до размера страницы в большую сторону. Параметр addr (рекомендуемый адрес) может быть равным NULL, - в этом случае ядро само назначает адрес в виртуальном адресном пространстве.

При использовании отображения на файл, параметр length имеет значение длины отображаемых данных; в случае, если размер файла меньше размера страницы, или отображается его последний небольшой фрагмент, то оставшаяся часть страницы заполняется нулями.

Страницы памяти могут флаги аттрибутов доступа:

  • чтение PROT_READ;
  • запись PROT_WRITE;
  • выполнение PROT_EXE;
  • ничего PROT_NONE.

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

Флаги mmap:

  • MAP_FIXED - требует, чтобы память была выделена по указаному в первом аргументе адресу; без этого флага ядро может выбрать адрес, наиболее близкий к указанному.
  • MAP_ANONYMOUS - выделить страницы в оперативной памяти, а не связать с файлом.
  • MAP_SHARED - выделить страницы, разделяемые с другими процессами; в случае с отображением на файл - синхронизировать изменения так, чтобы они были доступны другим процессам.
  • MAP_PRIVATE - в противоположность MAP_SHARED, не делать отображение доступным другим процессам. В случае отображения на файл, он доступен для чтения, а созданные процессом изменения, в файл не сохраняются.