4. Ответим на вопросы
• Как максимально точно понять сколько памяти использует
процесс?
• Куда девается вся свободная память?
• Если я раздаю файлы с диска зачем мне много памяти?
• Почему запись быстрее чтения?
• Почему перезапустить MySQL тяжелее чем MongoDB?
• Почему я могу потерять данные при записи на диск?
4
6. Немного терминов
︎Резидентная память (resident memory) – объём памяти, которая
находится непосредственно в оперативной памяти системы (RAM).
Анонимная память (anonymous memory) – память которая не
связана ни с каким файлом на диске (without backing store).
Page fault – ловушка (trap) обращения к памяти. Штатный механизм
при работе с виртуальной памятью.
6
7. Работа с памятью через страницы
Страница – это минимальная единица
памяти, с которой происходит работа.
Размер страницы 4KB.
Существуют Huge Pages – 2MB (не
будем рассматривать).
7
Адресное пространство
page
page
page
page
page
0x0
0xFFFFFFFF
…
4KB
page
8. Процесс работает с виртуальной памятью
8
Адресное пространство процесса
Основная память
RAM
Swap
устройство
Отображение памяти
Виртуальная память
Paging/swapping
• абстрактная модель;
• упрощает разработку;
• оставляем работу с настоящей памятью ОС;
• позволяет превышать размеры основной памяти.
12. Memory Zones
Из-за ограничений железа, ядро не может работать со всеми
страницами одинаково.
• ZONE_DMA
• ZONE_DMA32
• ZONE_NORMAL
Посмотреть какие зоны присутствуют:
# grep zone /proc/zoneinfo
Node 0, zone DMA
Node 0, zone DMA32
Node 0, zone Normal
Node 1, zone Normal
12
13. Page Cache
Динамический размер → съест всю вашу память.
По умолчанию все операции чтения и записи проходят через
Page Cache.
Посмотреть:
# free -m
total used free shared buffers cached
Mem: 64401 64101 299 0 161 60339
-/+ buffers/cache: 3600 60800
Swap: 0 0 0
# grep Cached /proc/meminfo
Cached: 61638200 kB
13
14. Read и Page Cache
14
read() syscall
Page
Cache
no, miss
Disk Storage
yes
Чтение происходит через Page Cache.
Работает со страницами памяти и файла.
mincore – системный вызов позволяет
посмотреть находятся ли страницы
файла в Page Cache.
vmtouch – позволяет посмотреть сколько
страниц в Page Cache’е:
# vmtouch /var/lib/db/index
Files: 1
Directories: 0
Resident Pages: 21365/21365 83M/83M 100%
Elapsed: 0.004477 seconds
hit
15. Write и Page Cache
По умолчанию запись происходит только в Page Cache (исключение
open() c O_SYNC).
Страницы в кеше помечаются как грязные (dirty).
Они сбрасываются на диск (writeback):
•︎через заданный интервал времени vm.dirty_expire_centisecs
(fsflush/pdflush);
• система испытывает нехватку памяти (kswapd);
• fsync() или msync();
• слишком много грязных страниц (vm.dirty_ratio и прочие).
# grep Dirty /proc/meminfo
…
Dirty: 9604 kB
… 15
16. Память процесса
Сегменты:
• stack;
• mmap;
• heap;
• bss;
• init data;
• text.
16
Stack
(grows downwards)
unallocated memory
Heap
(grows upwards)
Uninitialized data
(bss)
Initialized data
Text (program code)
top of stack
program break
(brk)
mmap region
RLIMIT_STACK
18. Virtual Memory Area (VMA)
Область памяти (virtual memory area VMA) – описывает пространство
адресов в памяти процесса (например 08048000-0804c000).
Права на области:
• Чтение (r);
• Запись (w);
• Исполнение (e).
Области видимости и доступа:
• приватные (p);
• общие (s).
18
21. malloc() и free()
glibc malloc() – выделяет анонимную память:
• heap – для аллокации маленьких объёмов (≤128KB);
• mmap() для остального.
free() – освобождает память.
22. Пример malloc() и brk()
Если в heap не хватает памяти – вызывается brk(), который расширяет
границы heap.
22
1. Перед выделением памяти 2. После выделения памяти
Heap
(grows upwards)
program break
(brk)
unallocated memory
Heap
(grows upwards)
new
program break
unallocated memory (brk)
110 KB
100 KB
23. mmap() и munmap()
23
mmap area
mmap(fd, …)
/var/lib/db/index
Виртуальная память процесса
Диск
mmap() – позволяет отображать содержимое файла на
адресное пространство процесса.
munmap() – освобождает память.
24. Флаги mmap()
Задаём видимость наших изменений:
• MAP_PRIVATE и указание файла;
• MAP_SHARED и указание файла.
Можем явно задать уровень доступа:
• PROT_READ;
• PROT_WRITE.
24
25. На самом деле Linux
не выделяет всю запрошенную
память сразу.
25
26. Page fault (demand paging)
Address space of a process
Unallocated
Only allocated
Page
Allocated and
mapped
memory
write syscall
TLB
MMU
Page Table
page fault RAM
translate to physical
Page
page mapping
Minor Page Fault – без обращения на диск.
27. Типы Page Fault
• Minor – без обращения на диск;
• major – с обращением на диск;
• invalid – ошибочное обращение (segmentation fault).
27
28. Page fault
Страница может быть в следующем состоянии:
1. Unallocated;
2. Allocated, but unmapped (not yet faulted);
3. Allocated, and mapped to main memory (RAM);
4. Allocated, and mapped to the physical swap device (disk);
Исходя из этого:
︎ RSS – размер 3-его пункта;
︎ Virtual Memory Size – сумма: 2 + 3 + 4.
28
29. Copy On Write (COW)
2. При попытке изменить страницу.
29
Parent Child
#0
#2
#1
free
#3
#0
#1
#2
#3
#4
Real Memory
free
#4
#0
#1
#2
#3
#4
1. После fork().
Parent Child
#0
#2
#1
change
#3
change
#1
#2
#3
#4
Real Memory
free
#4
#0
#1
#2
#3
#4
31. malloc() и работа с файлами
31
1. Читаем файл /var/m.log. 2. Ядро проверяет страницы в кеше.
read(fd, buf, 8192)
free
Kernel
free
free
free
/bin/ls
find
Page Cache
Heap pages
miss
3. Кеширует страницы файла.
Page Cache
m.log#0
free
/bin/ls
libc.so
free
m.log#1
Kernel
4. Копирует в user space буфер
Heap
filled
filled
Kernel
Disk
Storage
libc.so
32. malloc() и работа с файлами
• Используем больше памяти.
• Копирование в user space – больше CPU и переключений контекста.
32
33. mmap и работа с файлами
33
Простое отображение в Page Cache.
mmap()
#0
#1
Page Cache
m.log#0
free
/bin/ls
libc.so
m.log#1
mmap area
#2
34. mmap и minor page fault
34
Обращение с странице в первый раз,
которая уже в Page Cache.
mmap()
#0
#1
Page Cache
m.log#0
free
/bin/ls
libc.so
m.log#1
mmap area
#2
m.log#2
minor page fault
35. mmap и major page fault (1)
35
Обращение к странице в первый раз, которой нет в Page Cache
mmap()
#0
#1
Page Cache
m.log#0
free
/bin/ls
libc.so
m.log#1
mmap area
#2
free
major page fault
Page Cache
m.log#0
free
/bin/ls
libc.so
m.log#1
m.log#2
Disk
Storage
1. В Page Cache нет требуемой
страницы – major page fault.
2. Идём на диск и зачитываем
страницу в память.
36. mmap и major page fault (2)
36
3. Связываем страницу с Page Cache.
mmap()
#0
#1
Page Cache
m.log#0
free
/bin/ls
libc.so
m.log#1
mmap area
#2
m.log#2
37. mmap() выводы
37
• Позволяет работать с файлами как с памятью.
• “Lazy loading”.
• Быстрее – меньше системных вызовов и переключений
контекста.
• Экономит память.
• При завершении программы данные остаются в памяти.
39. Работаем с Page Cache
1. Работать в обход Page Cache:
• open(fd, O_DIRECT) – ходим мимо кеша (так делает MySQL с
InnoDB).
2. Подсказать ядру, что в ближайшее время мы не будем работать с
этим файлом и заставить его выгрузить страницы:
• posix_fadvide(fd, POSIX_FADV_DONTNEED);
• madvise(addr, MADV_DONTNEED);
• mincore().
3. Прибегнуть к помощи vmtouch (делает posix_fadvide):
vmtouch -e /var/lib/db/index
39
40. Пару слов про readahead
Управлять readahead можно:
• readahead();
• madvise();
• posix_fadvise();
• blockdev --report
blockdev --setra <value> <device>.
40
49. Почитать
49
Systems Performance:
Enterprise and the Cloud
Linux System Programming: Linux Kernel Development
Talking Directly to the Kernel
and C Library