#c #linux #memory
#c #linux #память
Вопрос:
Я пытаюсь глубоко разобраться в управлении виртуальной памятью в ОС Linux.
Я не совсем понимаю, как ОС определяет размер виртуальной машины для процесса.
Я знаю, что 32-разрядная ОС x86 может предоставить до 3 ГБ адресного пространства виртуальной машины… Всегда ли это так?
В моем случае у меня около 110 МБ физической памяти с 32-разрядным Linux, а мой основной процесс имеет адресное пространство виртуальной машины около 660 МБ. Однако в физической памяти (RSS моего процесса) находится только 50 МБ, поэтому моя физическая оперативная память не заполнена. Остальная часть бесплатна, и почти вся используется кешем страницы. Кажется, это нормальное поведение.
Если я проверю /proc/my_process_PID/smap, там будет несколько анонимных виртуальных машин объемом 8 МБ.
Моя реальная проблема заключается в том, что мне нужно добавить дополнительный 10-мегабайтный malloc в код, но, к сожалению, ООМ-убийца убивает мой процесс (из-за нехватки памяти)… Я думаю, что в виртуальной машине больше нет свободных доступных страниц для кучи, не так ли? Есть ли где-нибудь огромная утечка памяти?
Почему ОС так не увеличивает размер моей виртуальной машины процесса?
Для информации размер виртуальной машины не ограничен: ulimit -v: неограниченный
Комментарии:
1. И в чем именно заключается ваш вопрос; ожидаете ли вы, что ОС предоставит вам память, которой не существует? Есть ли на компьютере какое-либо «резервное хранилище» в виде файла подкачки или диска?
2. Чего я «не могу» понять, так это то, что моя ОС выделила около 660 МБ виртуальной памяти на 110 МБ физической памяти, и теперь ОС не позволяет мне выделять дополнительные 10 МБ в моем процессе. Почему он не увеличивает размер виртуальной машины до 670 МБ?
3. 660/110 превышен в шесть раз. Это сложно. Но помните: есть и другие процессы. (попробуйте выяснить, какой; может быть, вы сможете сократить там) И ОС хочет сохранить некоторую слабую память для вновь запущенных процессов и для буферов.
4. Я проверю наличие огромных утечек памяти с помощью журнала mtrace().
5. @ArnaudG: Виртуальная память объемом 660 МБ не обязательно полностью перегружена. Он включает в себя сопоставления разделяемой памяти, которые можно достаточно легко удалить.
Ответ №1:
У вас может быть 3 ГБ виртуальной памяти на процесс (приблизительно, во многих 32-разрядных Linux) и продолжать создавать новые процессы, занимающие гигабайт за гигабайтом виртуальной памяти. В ядре есть небольшие накладные расходы, но виртуальная память очень дешевая. Объем используемого вами адресного пространства, вероятно, не важен, и, вероятно, он не вызовет убийцу ООМ.
Однако в вашей системе не так много оперативной памяти. Когда вы начинаете использовать страницы в своем адресном пространстве (записывая их), ядро вынуждено находить физическую оперативную память для их сопоставления. Если физической оперативной памяти нет, ядро может удалить другие страницы из ОЗУ — либо заменить их, либо удалить. Но если он не может удалить какие-либо страницы, тогда он запускает ООМ-убийца.
Исчерпание адресного пространства приведет malloc
к возврату NULL
в мою систему вместо запуска ООМ-убийцы.
Похоже, ваш процесс просто использует слишком много оперативной памяти. RSS — это не объем памяти, который использует ваш процесс, это просто объем, который находится в физической оперативной памяти прямо сейчас. Если в вашем процессе происходит утечка памяти и он продолжает расти, RSS в конечном итоге перестанет расти, потому что для каждой новой страницы, которую вы используете, ядро удалит одну страницу из вашего процесса.
Попробуйте использовать профилировщик памяти, например Valgrind. Это поможет вам разобраться, о какой памяти вам следует беспокоиться (mallocs), а какую память вы можете игнорировать (общие библиотеки и другие файлы, отображаемые в память). Ядро (и / proc) не дадут вам достаточно подробностей.
Ответ №2:
Общий объем виртуальной памяти, доступной в системе Linux, составляет (примерно) RAM
swap space
— kernel overhead
. ОЗУ — это установленное вами оборудование, а накладные расходы ядра примерно постоянны (хотя и различаются в разных версиях ядра), поэтому единственный простой способ контролировать общее доступное пространство виртуальной машины — это добавлять или удалять пространство подкачки.
В дополнение к общему ограничению, существует также ограничение для каждого процесса виртуальной машины. Это настраивается и (по крайней мере, в 32-битном Linux) составляет не более 3 ГБ, но может быть немного меньше. ulimit -v
сообщит вам это ограничение или может быть использовано для его изменения.
Когда процесс запрашивает больше места для виртуальной машины (обычно через malloc), ядро проверяет все эти ограничения и, если какое-либо из них будет превышено, возвращает 0. С другой стороны, ООМ-убийца запускается только тогда, когда вы приближаетесь к общему пределу виртуальной машины. Однако, когда ООМ-убийца убивает вас, вы просто умираете — нет ошибки нехватки памяти или какой-либо возможности ее поймать.
Поэтому, если вы действительно сталкиваетесь с общим ограничением виртуальной машины и хотите избежать этого, вы можете либо выделить больше места подкачки, либо избавиться (убить или не запускать в первую очередь) от других процессов, которые используют много места для виртуальной машины, чтобы освободить его для вашей программы.
Комментарии:
1. Является ли максимальная виртуальная память намного больше, чем ОЗУ, из-за сопоставления памяти, например, сотен ГБ?