LINUX.ORG.RU

Фризы системы при исчерпании виртуальной памяти


0

4

Система: практически дефолтный Arch со всеми обновлениями, ядро 2.6.36, 32-разрядная сборка.

В первый раз столкнулся с проблемой случайно, когда Опера, проработав двое суток, выжрала всю доступную память и захотела еще. Комп работал без свопа. Переключиться в консоль смог, но залогиниться рутом — нет, логин выкидывало по 60-секундному таймауту.

Перезагрузился и решил попробовать воспроизвести ситуацию целенаправленно. Открыл на консолях top, iotop, vmstat и стал смотреть.

Проблема воспроизводится как со свопом, так и без, строго в момент исчерпания всей доступной виртуальной памяти.
Как воспроизводится: нагружаем систему любым способом. Я использовал запуск 5-и браузеров с несколькими десятками открытых вкладок.

Как происходит:
При исчерпании ОЗУ, система начинает выгружать страницы в своп: в статистике vmstat растут значения si и so. Повышается %wa, но фризов нет (хотя конечно иксами пользоваться невозможно, отрисовка окон лагает дико). Далее самое интересное. Своп заканчивается, в оперативе остаётся свободным 20-30 мегабайт. si и so падают до нуля, поскольку выгружать страницы уже некуда, и загружать обратно тоже практически некуда. Система работает в таком режиме некоторое время (несколько секунд), потом всё мгновенно фризится.
Top, iotop и vmstat продолжают обновляться, но очень медленно. Из них видно, что:
1) %wa почти 100%.
2) процессы продолжают выполняться, но при этом прочно сидят большую часть времени в состоянии uninterruptible sleep
3) iotop показывает интенсивный обмен данными
4) vmstat показывает высокое bi при практически нулевых si и so!
Ну в общем, понятно.

Выйти из этого состояния можно только либо выполнив killall имя_жирного_процесса, либо Ctrl+Alt+Del. Если в момент фриза вы не были залогинены в консоли, вам не повезло: логин висит больше минуты, а затем отменяется по таймауту. killall, кстати, тоже отрабатывает минуты 2.

Собственно, вопрос: что это такое и как это лечить?

У меня есть только одна гипотеза:
В память спроецировано множество файлов, начиная от исполняемых, и заканчивая различными файлами данных. Соответственно, все немодифицированные страницы памяти можно освободить, поскольку в любой момент можно подгрузить обратно с диска. В итоге при исчерпации ОЗУ и места в свопе, система этим и занимается: постоянно освобождает страницы отображенных в память файлов одних процессов, и загружает на их место страницы файлов других процессов, и так в бесконечном цикле.
Именно этим можно объяснить высокие значения bi.
Хотя я могуть быть в корне не прав.

В общем, какие есть соображения на сей счёт? Хотелось бы, во-первых, понять механизм возникновения фриза. И во-вторых, найти метод решения.

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

>Собственно, вопрос: что это такое и как это лечить?

sed -e '/swap/d' -i /etc/fstab && /sbin/swapoff -a

Своп в 21-м веке — это анахронизм.

anonymous
()
Ответ на: комментарий от anonymous

>Своп в 21-м веке — это анахронизм.

Я так вижу, что для анонимной школоты в 21-м веке мозг - это анахронизм.

Led ★★★☆☆
()
Ответ на: комментарий от Led

школота нынче бохатая пошла, памяти под 100500 гб воткнут и айда свопы вырубать

x0r ★★★★★
()

> метод решения.

Описан в man ulimit

Nastishka ★★★★★
()
Ответ на: комментарий от Umberto

А как же выключение через ресет? Вы ж никнейм видите - анонимус: они не спят

minakov ★★★★★
()

Ты мой брат-близнец. Весной я проделывал точь-в-точь то же самое.

Zenithar
()

Что удалось выяснить:

1. Вот такая программа:

#include <stdlib.h>
#include <stdio.h>

int main(void) {
	unsigned totalsize = 0;
	unsigned allocsize = 1024 * 1024 * 10;
	
	while (1) {
		char* p = malloc(allocsize);
		if (p) {
			totalsize += allocsize;
			printf("%uMiB\n", totalsize / (1024 * 1024));
		}
	}
}

Мгновенно сжирает 3 гига адресного пространства и просто крутится в цикле дальше. Реально память при это этом не выделяется. Сюрприз. Я видимо что-то пропустил в жизни Linux, просидев в криокамере, или просто с самого начала чего-то не знал — но выделять память malloc-ом, не гарантируя при этом наличия реальных страниц памяти или свопа — похоже на бред.

2. Курил ulimit и limits.conf. В конфиге ничего, похожего на лимиты выделения памяти не обнаружилось. В ulimit обнаружилась опция -v. К сожалению она не работает: ограничивает только размер виртуального адресного пространства отдельного процесса. А учётом предыдущего пункта, опция и вовсе бесполезна. Нужно, чтобы был ограничитель реального количества выделенных старниц, и не для процесса, а для всех процессов пользователя суммарно.

3. Вот такая программа:

#include <stdlib.h>
#include <stdio.h>

int main(void) {
	unsigned totalsize = 0;
	unsigned allocsize = 1024 * 1024 * 10;
	unsigned i;
	
	while (1) {
		char* p = malloc(allocsize);
		if (p) {
			totalsize += allocsize;
			printf("%uMiB\n", totalsize / (1024 * 1024));
			for (i =0; i < allocsize; i++)
				p[i] = (char)i;
		}
	}
}

за несколько секунд сжирает реальную доступную память и полность вешает систему. (Ctrl+Alt+F? не работают, если были запущены иксы. Если не были, то работают, но консоли висят и бесполезны. Ctrl+Alt+Del не работает тоже.) Если работать со свопом, полный висяк системы чуть отсрочивается, поскольку начинается активный свопинг и тормоза. Но в финале результат всё-равно тот же. Это в Archlinux. В Debian Lenny такую программу, крепко выматерившись в консоль, прибивает автоматический oom-killer.

В общем, копаю дальше. Вопросы, которые щас буду пытаться нагуглить:

1. Как заставить систему malloc-чить память только в случае, если её наличие гарантировано реально доступной в системе памятью. И кто «виноват» в текущем поведении malloc: glibc или ядро.

2. Как назначить квоты памяти, действующие per user. А также общую квоту, действующую на все процесс системы, кроме рутовский.

3. Как включить автоматический oom-killer в Archlinux.

geekless ★★
() автор топика
Ответ на: комментарий от Lumi

Еще нет: запостил, что вчера не дописал. Щас вкурю.

geekless ★★
() автор топика

Аналогичная проблема на сервере с lenny: две сотни одновременных подключений к веб-серверу и апач c php сжирают всю доступную память и своп. Oom-killer пытается убить самый жирный процесс - mysql - что, естественно, не помогает. Пока прикрутил скрипт, которые каждые 30 секунд мониторит LA, своп и память и при наступлении сабжа делает killall -9 php

leave ★★★★★
()
Ответ на: комментарий от Lumi

>http://catap.ru/blog/2009/05/03/about-memory-oom-killer/

http://catap.ru/blog/2009/05/05/about-memory-overcommit-memory/

Почитал, спасибо. Стало намного яснее. Хорошие статьи.


1. С malloc-м ясно. Ощущение, что Линус троллит пользователей таким способом. Покручу опции overcommit, посмотрю, что получится.

2. С квотами по-прежнему не ясно. Гугл релевантного ничего не нашел, по указанным ссылкам — тоже нет.

3. С oom-киллером ситуация оказалось еще запутаннее. Оказалось, что в Debian он работал, поскольку я тестировал бесконечный malloc на ненагруженной системе. В Arch, пока процессов запущено мало, всё тоже работает: при исчерпании памяти процесс прибивается как ему и положено. Если нагрузить систему хотя бы запуском хромиума, исчерпание памяти приводит к полному зависанию. alt-sysrq-f выводит сообщение о запуске OOM killer, но система висит дальше. alt-sysrq-e приводит к kernel panic (сфотографировать не смог, фотик разряжен). Похоже, причина не в кривых настройках, а в баге ядра.

geekless ★★
() автор топика
Ответ на: комментарий от Deleted

> а не общей картины для простого понимания.
И что?
Вместо своего мусорного сообщения, ты бы лучше взял бы да и описал общую картину для простого понимания.

Lumi ★★★★★
()
Ответ на: комментарий от Lumi

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

ты чего такой агрессивный? я написал, что тот материал для начинающего ничего толкового не привнесет в знания. ну да, потыкали носом в исходники и про формулы рассказали, а общей картины как не было, так и нет. и это нормально, когда обозначают малозначимость или бесполезность статьи. лично для меня такая критика обычно оказывает только позитивное влияние - заставляет задуматься о формате преподносимой информации.

Deleted
()

Поставил:
vm.overcommit_memory = 2
vm.overcommit_ratio = 90
Тестировал систему без свопа, со свопом 400MiB и со свопом 4400MiB. Всеми возможными способами, включая запуск всех установленных браузеров, воспроизведение звука, открытие больших файлов в GIMP, запуск бесконечного malloc-а (в том числе, от рута).
Фризов, зависаний, kernel panic-ов или срабатывания oom-киллера добиться не удалось никоим образом. Не смотря на интенсивный so и si, wa не превышало 30%. Система ведёт себя адекватно: при исчерпывании памяти отпинывает malloc-и NULL-ом, и процессы самостоятельно оканчивают жизнь самоубийством или же умеряют свои аппетиты.

Выводы:

1. Поставить по умолчанию режим «бесконечной памяти» vm.overcommit_memory = 0 додумались какие-то очень тонкие тролли. Хотя если это решение самого Торвальдса, я ничуть не удивлюсь — это в его стиле.
2. Слухи о бесполезности свопа в Linux оказались сильно преивеличены. Своп — торт, поскольку на его основе вычисляются лимиты доступной памяти. Ставить чем больше, тем лучше. Оставил пока 4гига. Поставил бы и больше, но надо партишены передвинуть сначала.
3. Оом киллер не нужен.

geekless ★★
() автор топика
Ответ на: комментарий от Lumi

>Что именно не получилось с квотами?

Не получилось нагуглить сабж.
Требуется: назначать UID-ам квоту на количество занятой всеми процессами с данным UID-ом памяти. Т.е. чтобы процессы данного пользователя в сумме не занимали больше, чем, например, 1000 мегабайт.
Вопрос: есть ли такой механизм в Linux, и если есть, через что настраивается.
man limits.conf и man getrlimit смотрел — не то. Там, если я правильно понимаю, даются лимиты только per process, а требуется — per UID.

geekless ★★
() автор топика
Ответ на: комментарий от leave

две сотни одновременных подключений к веб-серверу и апач c php сжирают всю доступную память и своп.

Вам не рассказывали про memory_limit (или как оно там) в php.ini?

no-dashi ★★★★★
()
Ответ на: комментарий от leave

>две сотни одновременных подключений к веб-серверу и апач c php сжирают всю доступную память и своп

Выделил жирным проблемные места. Избавишься от них — избавишься от проблемы.

anonymous
()
Ответ на: комментарий от Led

>Я так вижу, что для анонимной школоты в 21-м веке мозг - это анахронизм.

Консервативно-агрессивно настроенное лоробыдло детектед. Батя, скажи, зачем нужен своп в 21-м веке при работе? swapon /dev/sdX в скрипте для хибернейта написать не проблема, ровно как и swapoff -a в скрипте «просыпания». Зато будет меньше дебильных воплей «у миня гибабаит памети свабодный, а в свопе пицот мигабайт занято!!1»

anonymous
()
Ответ на: комментарий от anonymous

Теперь мне абсолютно ясно, что режим vm.overcommit_memory = 0 создан специально для ЛОРовских анонимусов, не умеющих читать.

geekless ★★
() автор топика
Ответ на: комментарий от no-dashi

>Вам не рассказывали про memory_limit (или как оно там) в php.ini?

32 мегабайта. 8 гигов памяти на сервере. ~700 виртхостов.

leave ★★★★★
()
Ответ на: комментарий от anonymous

ути-пути, опять адепты эрланга в треде? вы еще забыли посоветовать сменить муксуль на коучдб

leave ★★★★★
()

Скажите, а у кого-нибудь падает (сильно) производительность системы, как только начинает использоваться свап (например, 2 Гб ОЗУ, 300 Мб Swap) на .35 ядре. Такая проблема/фича появилась в Бубунте 10.10. Когда памяти хватает, система работает быстро, как только задел свап - система начинает фризить. Мне интересно, пора валить с Бубунты или дело в ядре?

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.