13 января 2009

И снова о памяти в Linux - /proc/meminfo

В продолжение поста о команде free, посмотрим на более полный источник об использовании памяти - специальную виртуальную файловую систему /proc, являющуюся общей точкой доступа к структурам данных ядра, а именно - на информацию /proc/meminfo. Вывод команды cat:
[andrey@server1 ~]$  cat /proc/meminfo
MemTotal: 1945312 kB
MemFree: 48980 kB
Buffers: 2248 kB
Cached: 171092 kB
SwapCached: 256 kB
Active: 622380 kB
Inactive: 32504 kB
HighTotal: 1048256 kB
HighFree: 3176 kB
LowTotal: 897056 kB
LowFree: 45804 kB
SwapTotal: 2048276 kB
SwapFree: 2047868 kB
Dirty: 2696 kB
Writeback: 400 kB
AnonPages: 481592 kB
Mapped: 137244 kB
Slab: 34244 kB
PageTables: 7276 kB
NFS_Unstable: 0 kB
Bounce: 0 kB
CommitLimit: 2433156 kB
Committed_AS: 1277084 kB
VmallocTotal: 114680 kB
VmallocUsed: 14232 kB
VmallocChunk: 99948 kB
Пройдемся сверху вниз с некоторыми комментариями по части из этих значений.

MemTotal - Доступный объем оперативной памяти. Часть физически доступной памяти резервируется во время запуска системы ядром и не входит в указанный здесь объем:
[root@server1 ~]# grep Memory: /var/log/dmesg
Memory: 1941740k/1965760k available
(2097k kernel code, 22716k reserved,
877k data, 228k init, 1048256k highmem)
MemFree - Какой объем памяти не используется и доступен для немедленного выделения процессам. Ядро Linux старается использовать доступную память максимально эффективно, и, по умолчанию, достаточно большой объем ОЗУ, потенциально доступный для приложений, может быть занят под кэш и буферы. Объем свободной памяти в несколько десятков мегабайт на машинах с гигабайтами оперативной памяти - вполне типичная картина для Linux. В 32-разрядной операционной системе MemFree=LowFree+HighFree.

Buffers - область ОЗУ, занятая хранением данных, ожидающих записи на диск. Буфер позволяет приложениям продолжать выполнение своей задачи не дожидаясь момента когда данные будут физически записаны на диск. Обычно размер около 20Мб.

Cached - Объем занятый в ОЗУ под кэш чтения страниц с диска (файлы, директории, файлы блочных устройств, данные, относящиеся к механизму IPC, данные процессов уровня пользователя, сброшенных в область подкачки). Не включает в себя SwapCached.

SwapCached - Объем памяти, который однажды был помещен в область подкачки, но потом перенесен обратно в ОЗУ. Однако данные все еще присутствуют в swap, и при необходимости этот объем памяти может быть вновь освобожден без необходимости тратить ресурсы на "дорогие" операции ввода/вывода.

Active - Объем памяти, занятый в ОЗУ наиболее часто используемыми страницами памяти. Иными словами, эти страницы памяти активно используются процессами и будут освобождаться только в случае крайней необходимости.

Inactive - Объем памяти, занятый в ОЗУ не используемыми в настоящий момент страницами. Эти страницы считаются наиболее подходящими для выгрузки в swap и освобождения в случае необходимости.

High{Total,Free}, Low{Total,Free} - MemTotal=HighTotal+LowTotal. Вывод команды cat /proc/meminfo получен на 32-разрядной операционной системе. Модель использования памяти в 32-разрядном и 64-разрядном ядрах отличается. Ниже я привел рисунок, показывающий эти отличия:


В 32-р архитектуре ядро Linux может напрямую адресовать только первый гигабайт физической памяти. На рисунке ZONE_NORMAL - это и есть область памяти объемом LowTotal:897056 kB. Число меньше гигабайта за счет зарезервированных ядром областей памяти. Из оставшегося объема нужно вычесть 1Мб, используемый BIOS и устройствами ввода/вывода, а также 16Mб ZONE_DMA для совместимости с ограничениями устройств на шине ISA. Память "выше" первого гигабайта - ZONE_HIGHMEM (HighTotal:1048256 kB). Доступ к ней осуществляется через отображение на первый гигабайт ОЗУ. Отображение "прозрачно" для приложений, но вызывает небольшую потерю производительности. ZONE_NORMAL используется для тех же нужд что и зона ZONE_HIGHMEM, плюс для собственных структур ядра. В 64-разрядных архитектурах зона ZONE_HIGHMEM всегда пуста.

Swap{Total, Free} - SwapTotal - это общий объем области подкачки (как в разделе подкачки, так и в swap-файлах, если они используются). Как и в случае с ОЗУ, ядро Linux старается использовать область подкачки максимально эффективно. Иногда факт использования части области подкачки еще не означает того, что память является "узким местом" производительности системы. Один из способов влиять на агрессивность использования swap - это парметр vm.swappiness. Чем больше процент swappiness, тем активнее будет выгрузка в swap. По умолчанию в RHEL5 это число 60%. Предпочтительно использовать более агрессивную политику выгрузки в область подкачки, когда вы, например, на рабочей станции большую часть времени работаете с одним большим пакетом ПО и редко переключаетесь на другие задачи. Пример из области серверов - машина с ограниченным ОЗУ, выполняющая какие-то пакетные задания (процессы, находящиеся долгое время в состоянии S). На серверах с большим объемом ОЗУ увеличения swappiness может свести все выгоды использования swap "на нет" из-за активного использования дисковой подсистемы и процессорного времени для поиска и сброса на диск неактивных страниц памяти.

Dirty - Измененные ("грязные") страницы, находящиеся в ОЗУ, но еще не сброшенные на диск. За процедуру записи на диск отвечает группа потоков ядра pdflush. В системе должно работать минимум два и максимум восемь потоков pdflush. Посмотреть текущее число потоков можно:
[root@server1 ~]# cat /proc/sys/vm/nr_pdflush_threads
2
Дополнительные потоки создаются в зависимости от текущей нагрузки ввода/вывода. Команда sync и "магическая" комбинация Alt-SysRq-S сбрасывает все "грязные" страницы и буферы. Число, хранящееся в vm.dirty_background_ratio (по умолчанию 10%), задает какой процент от ОЗУ потоки pdflush должны сбрасывать на диск. Чем больше процент, тем реже происходит обращение к диску. Второй из важных параметров, влияющих на pdflush, это процент от объема ОЗУ, при котором стартует сам процесс сброса на диск - vm.dirty_ratio.

Writeback - Страницы памяти, которые в настоящий момент сбрасываются на диск.

AnonPages - Анонимные страницы - это, как правило, данные, используемые программами и не ассоциированные с каким-либо файлом. Наряду со страницами, объем которых указан в Inactive, это первые кандидаты на попадание в область подкачки. Анонимные страницы нередко используются несколькими процессами. Самый распространенный пример - fork() при создании нового процесса. Число анонимных страниц для конкретного процесса можно вычислить как разницу между размером резидентной части (resident) и разделяемыми страницами (share) в выводе /proc/PID/statm (информация о состоянии памяти в страницах). Например:
[root@server1 vm]# cat /proc/$(pidof sshd)/statm
1763 258 161 93 0 130 0
Получается что число анонимных страниц для sshd = 258 - 161 = 97 или 388Кб. Подробнее - man proc.

Mapped - Общий объем памяти, привнесенный в виртуальное адресное пространство процессов при помощи mmap (например, библиотеки).

Slab - объем памяти, занятый под различные структуры ядра небольшого объема, для которых не оптимально выделять по целой странице памяти. По умолчанию в 32-р системах размер страницы - 4Кб, и этот объем является квантом памяти при ее выделении. Подробнее информацию о slab-кэше можно посмотреть при помощи утилиты vmstat с ключем -m, утилиты slabtop или через /proc/slabinfo.

PageTables - Объем памяти, зарезервированный под Таблицу Страниц.

NFS_Unstable - Данный параметр относится к клиенту NFS v3+, реализованному в ядре Linux, и показывает, какой объем данных, отправленных клиентом серверу, еще не был записан на диск. Клиент должен кэшировать эти данные до поступления подтверждения от сервера.

CommitLimit - Объем памяти, который может быть выделен системой. Вычисляется на основе vm.overcommit_ratio (по умолчанию - 50%) и размера области подкачки. Формула имеет следующий вид CommitLimit = ( vm.overcommit_ratio * объем_ОЗУ) + область_подкачки. Этот лимит соблюдается только при "строгой" политике выделения памяти (vm.overcommit_memory=2). По умолчанию используется "эвристическая" политика (vm.overcommit_memory=0).

Committed_AS - Сколько памяти выделено всем процессам, даже если они эту память не используют в полном объеме. Иными словами, данный параметр показывает, сколько при текущей загрузке системы требуется ОЗУ, если процессы реально захотят использовать выделенную память для того, чтобы избежать core dump по причине отсутствия памяти (OOM). Дело в том что, когда процесс требует - ядро подтверждает выделение требуемого объема памяти (только если не используется "строгая" политика. В этом случае проверяем, не исчерпан ли CommitLimit) без выделения ОЗУ. Реально память выделяется постранично только лишь когда процесс пытается что-то записать в выделенную до этого память. Этот механизм называется overcommitment. Более подробно см. /usr/share/doc/kernel-doc-*/Documentation/vm/overcommit-accounting.

VmallocTotal - общее число виртуального пространства, доступного для vmalloc.

VmallocUsed - объем использованного пространства vmalloc.

VmallocChunk - наибольший свободный непрерывный блок внутри пространства vmalloc.

Литература:
  • Ядро Linux. 3-е издание, Даниель Бовет, Марко Чезати, БХВ-Петербург, 2007
  • Optimizing Linux® Performance: A Hands-On Guide to Linux® Performance Tools, Phillip G. Ezolt, Pearson PTR, 2005
  • Linux System Programming, Robert Love, O’Reilly, 2007
  • /usr/share/doc/kernel-doc-*/Documentation/

24 комментария:

axet комментирует...

Чем это вы так Андрей красиво рисуете, надеюсь это не visio? :)

Andrey Markelov комментирует...

В качестве "замены" Visio я использую Dia. Павда это не совсем полноценная замена. Конкретно же последние 2 картинки были "на скорую руку" нарисованы за 5 минут в KolourPaint. Для "быстрой и грязной" работы вполне норм.

Анонимный комментирует...

Очень хорошая статья, спасибо

hubbitus комментирует...

Круто, действительно просто и понятно все описано, спасибо большое.

А что это за резерв в 128Мб на 32 битных системах? Зачем, для чего? И со стрелочками так и не понял, он все же из первого гига или из HIGHMEM выделяется?

Анонимный комментирует...

а подскажите почему шаред память (IPC) занятая оракловым процессом (структуры SGA) в линуксе показывается как cached ?

Yo! комментирует...

>Cached - Объем занятый в ОЗУ под кэш чтения страниц с диска (файлы, директории, файлы блочных устройств, данные, относящиеся к механизму IPC

а вот не подскажите, есть ли простой способ отделить "относящиеся к механизму IPC" от остального кешед ?

Andrey Markelov комментирует...

2 hubbitus
> же из первого гига или из HIGHMEM выделяется?

HIGHMEM через эту область памяти отображается на 1й гигабайт

2 Анонимный

> а подскажите почему шаред память (IPC) занятая оракловым процессом

Это скорее в oracle metalink нужно а не в доке по Linux искать..

2 Yo!

> отделить "относящиеся к механизму IPC" от остального

С ходу - не скажу. Не знаю. Наверно копать нужно в сторону kernel.shm*, ipcs...

Анонимный комментирует...

Классная статья, спасибо. Один вопрос: в чём разница между Dirty и Buffers? И те, и другие сбрасываются на диск.

Woland комментирует...

Хорошая статья. Спасибо.

Такой вот вопрос: на машине гиг памяти. При этом, видимо, 128 метров таки резервируется для отображения хаймема, и как результат, этот хаймем появляется. :+)

HighTotal: 129432 kB
HighFree: 240 kB
LowTotal: 896616 kB
LowFree: 85488 kB

Можно ли заставить ядро использовать весь гигабайт как лоумем? Откуда вообще взялось такое поведение?

Andrey Markelov комментирует...

2 Анонимный

Одно - страницы памяти, Другое - дисковы буфер

2 Woland

Ограничение архитектуры. Поставьте 64-р ОС.

Woland комментирует...

Но почему? Если 32-битная ОС может прямо адресовать гигабайт.

Andrey Markelov комментирует...

> Если 32-битная ОС может прямо адресовать гигабайт

ЧТо такое "ОС может адресовать прямо"?

Схема организации памяти в любой современной ОС доcтаточно сложная. Если говорить о Linux то есть понятие логического (инструкции машинного языка), виртуального (32-р целое без знака - до 4Гб) и физического адреса (начиная с Pentium Pro - 64 Гб).

Суть вашего вопроса в том что вы опасаетесь что "тереяете" 128M? Вы их не теряете HighTotal+ LowTotal= 1Гб.

Woland комментирует...

Переформулирую. Вы написали, что лоумем может вмещать до гигабайта. 128М резервируются для маппинга хаймема. Но в чём смысл резервирования этих мегабайт и создания хаймема, если вся память умещается в лоумем?

Andrey Markelov комментирует...

> Переформулирую. Вы написали, что лоумем может вмещать до гигабайта.

Нет. Я писал что High - это больше гигабайта. А LowTotal:897056

> если вся память умещается в лоумем?

Не помещается.

Лучше обратитесь к первоисточнику - книге "Ядро Linux" на которую я ссылался в конце поста.

Georgyi комментирует...

Написано доступно и понятно.
Мне не понятно почему на моей 32 р машине из 4 Гб видно всего 2852440 kB?
-------------------------
dmidecode -t memory
# dmidecode 2.9
SMBIOS 2.3 present.

Handle 0x0007, DMI type 5, 24 bytes
Memory Controller Information
Error Detecting Method: 64-bit ECC
Error Correcting Capabilities:
None
Supported Interleave: One-way Interleave
Current Interleave: One-way Interleave
Maximum Memory Module Size: 1024 MB
Maximum Total Memory Size: 4096 MB
Supported Speeds:
70 ns
60 ns
Supported Memory Types:
Other
Unknown
Standard
FPM
EDO
Parity
ECC
SIMM
DIMM
Burst EDO
SDRAM
Memory Module Voltage: 3.3 V
Associated Memory Slots: 4
0x0008
0x0009
0x000A
0x000B
Enabled Error Correcting Capabilities:
None

Handle 0x0008, DMI type 6, 12 bytes
Memory Module Information
Socket Designation: CH A DIMM0
Bank Connections: 0 0
Current Speed: Unknown
Type: DIMM SDRAM
Installed Size: 1024 MB (Double-bank Connection)
Enabled Size: 1024 MB (Double-bank Connection)
Error Status: OK

Handle 0x0009, DMI type 6, 12 bytes
Memory Module Information
Socket Designation: CH A DIMM1
Bank Connections: 0 0
Current Speed: Unknown
Type: DIMM SDRAM
Installed Size: 1024 MB (Double-bank Connection)
Enabled Size: 1024 MB (Double-bank Connection)
Error Status: OK

Handle 0x000A, DMI type 6, 12 bytes
Memory Module Information
Socket Designation: CH B DIMM0
Bank Connections: 0 0
Current Speed: Unknown
Type: DIMM SDRAM
Installed Size: 1024 MB (Double-bank Connection)
Enabled Size: 1024 MB (Double-bank Connection)
Error Status: OK

Handle 0x000B, DMI type 6, 12 bytes
Memory Module Information
Socket Designation: CH B DIMM1
Bank Connections: 0 0
Current Speed: Unknown
Type: DIMM SDRAM
Installed Size: 1024 MB (Double-bank Connection)
Enabled Size: 1024 MB (Double-bank Connection)
Error Status: OK

Handle 0x0041, DMI type 16, 15 bytes
Physical Memory Array
Location: System Board Or Motherboard
Use: System Memory
Error Correction Type: None
Maximum Capacity: 4 GB
Error Information Handle: 0x0040
Number Of Devices: 4

Handle 0x0043, DMI type 17, 27 bytes
Memory Device
Array Handle: 0x0041
Error Information Handle: 0x0040
Total Width: 64 bits
Data Width: 64 bits
Size: 1024 MB
Form Factor: DIMM
Set: 1
Locator: J6G1
Bank Locator: CHANNEL A DIMM0
Type: DDR
Type Detail: Synchronous
Speed: 400 MHz (2.5 ns)
Manufacturer: Manufacturer1
Serial Number: SerNum1
Asset Tag: AssetTagNum1
Part Number: PartNum1

Handle 0x0045, DMI type 17, 27 bytes
Memory Device
Array Handle: 0x0041
Error Information Handle: 0x0040
Total Width: 64 bits
Data Width: 64 bits
Size: 1024 MB
Form Factor: DIMM
Set: 2
Locator: J6G2
Bank Locator: CHANNEL A DIMM1
Type: DDR
Type Detail: Synchronous
Speed: 400 MHz (2.5 ns)
Manufacturer: Manufacturer2
Serial Number: SerNum2
Asset Tag: AssetTagNum2
Part Number: PartNum2

Handle 0x0047, DMI type 17, 27 bytes
Memory Device
Array Handle: 0x0041
Error Information Handle: 0x0040
Total Width: 64 bits
Data Width: 64 bits
Size: 1024 MB
Form Factor: DIMM
Set: 1
Locator: J6H1
Bank Locator: CHANNEL B DIMM0
Type: DDR
Type Detail: Synchronous
Speed: 400 MHz (2.5 ns)
Manufacturer: Manufacturer3
Serial Number: SerNum3
Asset Tag: AssetTagNum3
Part Number: PartNum3

Handle 0x0049, DMI type 17, 27 bytes
Memory Device
Array Handle: 0x0041
Error Information Handle: 0x0040
Total Width: 64 bits
Data Width: 64 bits
Size: 1024 MB
Form Factor: DIMM
Set: 2
Locator: J6H2
Bank Locator: CHANNEL B DIMM1
Type: DDR
Type Detail: Synchronous
Speed: 400 MHz (2.5 ns)
Manufacturer: Manufacturer4
Serial Number: SerNum4
Asset Tag: AssetTagNum4
Part Number: PartNum4
------------------------
cat /proc/meminfo
MemTotal: 2852440 kB
MemFree: 1749984 kB
Buffers: 217368 kB
Cached: 535564 kB
SwapCached: 0 kB
Active: 593368 kB
Inactive: 414744 kB
HighTotal: 1964220 kB
HighFree: 1166880 kB
LowTotal: 888220 kB
LowFree: 583104 kB
SwapTotal: 3014648 kB
SwapFree: 3014648 kB
Dirty: 160 kB
Writeback: 0 kB
AnonPages: 255188 kB
Mapped: 9424 kB
Slab: 65432 kB
SReclaimable: 51968 kB
SUnreclaim: 13464 kB
PageTables: 1932 kB
NFS_Unstable: 0 kB
Bounce: 0 kB
WritebackTmp: 0 kB
CommitLimit: 4440868 kB
Committed_AS: 448500 kB
VmallocTotal: 114680 kB
VmallocUsed: 9948 kB
VmallocChunk: 104452 kB
HugePages_Total: 0
HugePages_Free: 0
HugePages_Rsvd: 0
HugePages_Surp: 0
Hugepagesize: 2048 kB
DirectMap4k: 12288 kB
DirectMap2M: 905216 kB
---------------------------
cat /proc/cpuinfo
processor : 0
vendor_id : GenuineIntel
cpu family : 15
model : 3
model name : Intel(R) Pentium(R) 4 CPU 3.40GHz
stepping : 4
cpu MHz : 3400.000
cache size : 1024 KB
physical id : 0
siblings : 2
core id : 0
cpu cores : 1
apicid : 0
initial apicid : 0
fdiv_bug : no
hlt_bug : no
f00f_bug : no
coma_bug : no
fpu : yes
fpu_exception : yes
cpuid level : 5
wp : yes
flags : fpu vme de pse tsc msr pae mce cx8 apic mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe constant_tsc pebs bts pni monitor ds_cpl cid xtpr
bogomips : 6800.16
clflush size : 64
power management:

processor : 1
vendor_id : GenuineIntel
cpu family : 15
model : 3
model name : Intel(R) Pentium(R) 4 CPU 3.40GHz
stepping : 4
cpu MHz : 3400.000
cache size : 1024 KB
physical id : 0
siblings : 2
core id : 0
cpu cores : 1
apicid : 1
initial apicid : 1
fdiv_bug : no
hlt_bug : no
f00f_bug : no
coma_bug : no
fpu : yes
fpu_exception : yes
cpuid level : 5
wp : yes
flags : fpu vme de pse tsc msr pae mce cx8 apic mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe constant_tsc pebs bts pni monitor ds_cpl cid xtpr
bogomips : 6799.01
clflush size : 64
power management:

Andrey Markelov комментирует...

А при компиляции ядра что было указано в параметрах CONFIG_HIGHMEM* ?

Georgyi комментирует...

cat /boot/config-2.6.27.9-159.fc10.i686.PAE |grep CONFIG_HIGHMEM
# CONFIG_HIGHMEM4G is not set
CONFIG_HIGHMEM64G=y
CONFIG_HIGHMEM=y
В биосе естественно все 4 Гб видно.

Andrey Markelov комментирует...

"На вскидку" в голову ничего не приходит. возможно особенности вашей материнской платы/чипсета/etc... "С ходу" затрудняюсь что-либо еще сказать.

Анонимный комментирует...

Georgyi пишет...

Написано доступно и понятно.
Мне не понятно почему на моей 32 р машине из 4 Гб видно всего 2852440 kB?
===============
Дело в том, что устройства шины PCI отображаются в "память". Очень много занимает видео-карта. Отображаются они "не впритык" - есть куча дырок. Пока памяти было мало, это не мешало.
4 Гб - это максимальный размер адресуемой памяти для 32р. У вас он совпадает по размеру с реальной и происходит "перекрытие". Возможно что при запуске 2-х и более задач память все-таки используется, но я не интересовался этим вопросом.

Роман комментирует...

Спасибо, то что искал, а то нигде не расписано толком чем Buffers от Cached отличается

Анонимный комментирует...

Статья наглядная, понятная,
однако сколько памяти может быть выделено на один процесс? или это вопрос к самому приложению?

Andrey Markelov комментирует...

> однако сколько памяти может быть выделено на один процесс?

Ответ на ваш вопрос есть в kbase:
http://kbase.redhat.com/faq/docs/DOC-6571

Анонимный комментирует...

Спасибо за интересную статью, но по моему как то сложновато написано. Я честно говоря так и не получил для себя ответа на вопрос: "как определить объем свободной (незанятой) памяти?". Может быть не очень корректно выражаюсь, но меня как системного администратора который мониторит загрузку сервера интересует банальный вопрос: "достаточно ли памяти на сервере для работы приложений?". Хотелось бы как то понять сколько в текущий момент занято памяти под приложения и сколько соответственно еще свободно и может быть использовано для запуска других приложений.

Andriy Samilyak комментирует...

2 Анонимный

Посмотрите вот здесь о том, как корректно определить свободную память