Это как Linux пейджинг должен вести себя?


26

Когда моя система Linux приближается к пейджингу (то есть, в моем случае, 16 ГБ ОЗУ почти заполнены, 16 ГБ подкачка полностью пуста), если новый процесс Х пытается выделить некоторую память, система полностью блокируется. То есть до тех пор, пока непропорциональное количество страниц (по отношению к общему размеру и скорости запросов на выделение памяти X) не будет заменено. Обратите внимание, что не только графический интерфейс пользователя перестает отвечать на запросы, но даже такие базовые службы, как sshd, полностью блокируются.

Это две части кода (по общему признанию, грубые), которые я использую, чтобы вызвать такое поведение более «научным» способом. Первый получает два числа x, y из командной строки и перераспределяет и инициализирует несколько фрагментов по y байтов, пока не будет выделено более x общих байтов. А потом просто спит бесконечно. Это будет использовано, чтобы вывести систему на грань пейджинга.

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

int main(int argc, char** argv) {
   long int max = -1;
   int mb = 0;
   long int size = 0;
   long int total = 0;
   char* buffer;

   if(argc > 1)
     {
       max = atol(argv[1]);
       size = atol(argv[2]);
     }
   printf("Max: %lu bytes\n", max);
   while((buffer=malloc(size)) != NULL && total < max) {
       memset(buffer, 0, size);
       mb++;
       total=mb*size;
       printf("Allocated %lu bytes\n", total);       
   }      
   sleep(3000000);
   return 0;
}

Второй кусок кода делает именно то, что делает первый, за исключением того, что он имеет sleep(1);право после printf(я не собираюсь повторять весь код). Этот будет использоваться, когда система находится на грани подкачки, чтобы заставить ее обмениваться страницами «мягким» способом, то есть, медленно запрашивая выделение новых кусков памяти (так что система, безусловно, должна иметь возможность обмениваться страницами и не отставать от новых запросов).

Итак, скомпилировав две части кода, давайте назовем соответствующие exes fasteater и sloweater, давайте сделаем так:

1) запустите ваш любимый графический интерфейс (конечно, не обязательно)

2) запустить какой-нибудь измеритель памяти / своп (например watch -n 1 free)

3) начать несколько экземпляров, fasteater x yгде х имеет порядок гигабайт, а у имеет порядок мегабайт. Делайте это до тех пор, пока вы почти не заполните баран.

4) запустить один экземпляр sloweater x y, опять же, где х порядка гигабайт, а у порядка мегабайт.

После шага 4) то, что должно произойти (и это всегда происходит для моей системы), состоит в том, что сразу же после исчерпания памяти, система полностью блокируется. GUI заблокирован sshd заблокирован и т. д. НО, не навсегда! После того, как sloweater завершит свои запросы на выделение ресурсов, система вернется к жизни (после нескольких минут блокировки, а не секунд ...) в такой ситуации:

а) баран полон

б) своп тоже почти полный (помните, он был пустым в начале)

в) без вмешательства убийцы.

И обратите внимание, что раздел подкачки находится на SSD. Таким образом, система, по-видимому, не может постепенно перемещать страницы из оперативной памяти в подкачку (предположительно из только что спящих быстродействующих устройств), чтобы освободить место для медленных (и всего лишь несколько мегабайт) запросов медленного едока.

Теперь, кто-то поправит меня, если я ошибаюсь, но это не похоже на поведение современной системы в таких условиях. Кажется, он ведет себя как старые системы (обратно), когда не было поддержки подкачки страниц, а система виртуальной памяти просто заменяла все пространство памяти какого-либо процесса вместо нескольких страниц.

Может кто-нибудь тоже это проверить? И, может быть, кто-то, кто также имеет систему BSD.

ОБНОВЛЕНИЕ 1 Я последовал совету Марка Плотника, приведенному ниже в комментариях, и я начал vmstat 1 >outперед тем, как приступить к тестированию страниц. Вы можете увидеть результат ниже (я вырезал всю начальную часть, где оперативная память заполнена без участия обмена):

procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
0  0   6144 160792      8 272868    0    0     0     0  281 1839  1  0 99  0  0
0  0   6144 177844      8 246096    0    0     0     0  425 2300  1  1 99  0  0
0  0   6144 168528      8 246112    0    0    16     0  293 1939  1  0 99  0  0
0  0   6144 158320      8 246116    0    0     0     0  261 1245  0  0 100  0  0
2  0  10752 161624      8 229024    0 4820 17148  4820  845 3656  1  2 97  0  0
2  0  10752 157300      8 228096    0    0 88348     0 2114 8902  0  5 94  1  0
0  0  10752 176108      8 200052    0    0 108312     0 2466 9772  1  5 91  3  0
0  0  10752 170040      8 196780    0    0 17380     0  507 1895  0  1 99  0  0
0 10  10752 160436      8 191244    0    0 346872    20 4184 17274  1  9 64 26  0
0 29 12033856 152888      8 116696 5992 15916880 1074132 15925816 819374 2473643  0 94  0  6  0
3 21 12031552 295644      8 136536 1188    0 11348     0 1362 3913  0  1 10 89  0
0 11 12030528 394072      8 151000 2016    0 17304     0  907 2867  0  1 13 86  0
0 11 12030016 485252      8 158528  708    0  7472     0  566 1680  0  1 23 77  0
0 11 12029248 605820      8 159608  900    0  2024     0  371 1289  0  0 31 69  0
0 11 12028992 725344      8 160472 1076    0  1204     0  387 1381  0  1 33 66  0
0 12 12028480 842276      8 162056  724    0  3112     0  357 1142  0  1 38 61  0
0 13 12027968 937828      8 162652  776    0  1312     0  363 1191  0  1 31 68  0
0  9 12027456 1085672      8 163260  656    0  1520     0  439 1497  0  0 30 69  0
0 10 12027200 1207624      8 163684  728    0   992     0  411 1268  0  0 42 58  0
0  9 12026688 1331492      8 164740  600    0  1732     0  392 1203  0  0 36 64  0
0  9 12026432 1458312      8 166020  628    0  1644     0  366 1176  0  0 33 66  0

Как вы можете видеть, как только своп вступает в действие, происходит огромная свопинг в 15916880 Кбайт одновременно, который, я думаю, длится в течение всего периода остановки системы. И все это, по-видимому, вызвано процессом (замедлителем), который просто запрашивает 10 МБ каждую секунду.

ОБНОВЛЕНИЕ 2: Я сделал быструю установку FreeBSD и повторил ту же схему размещения, что и в Linux ... и все было так гладко, как и должно быть. FreeBSD меняла страницы постепенно, в то время как медленный сервер выделял все свои 10 МБ порции памяти. Ни одного заминки ... WTF здесь происходит ?!

ОБНОВЛЕНИЕ 3: Я подал ошибку с помощью средства отслеживания ошибок ядра. Кажется, это привлекает внимание, так что ... пальцы скрещены ...


2
Как я уже говорил, все заблокировано. Я пытался ssh'ing из другой системы, просто время ожидания.
Джон Террагон

2
Если я запускаю vmstat 1 с выводом stdout, я думаю, что он остановится. Но вы правы, я мог бы просто начать vmstat 1>somefileнепосредственно с системы, а затем посмотреть, что она сообщает после того, как система вернется к жизни. Я попробую это.
Джон Террагон

2
Я использовал vmstat. Результаты в обновлении выше.
Джон Террагон,

3
swappinessпо умолчанию 60 (не то, чтобы изменение дало лучший результат). Ядро, используемое в vmstatпрогоне: 4.14.35, но я пробовал 4.15, 4.16 и даже вернулся к серии 4.0 (!): Всегда одинаковое поведение. И дело не в том, что я использую какой-то странный дистрибутив, это просто debian. Я не использую образы ядра из Debian (не то, что у меня есть необычные конфиги), но я попробовал одно из тех же ... поведения.
Джон Террагон

2
Очень интересное обсуждение ошибки ядра! И похоже, что вы изолировали эту проблему для замены раздела, зашифрованного с помощью LUKS. Возможно, вы захотите отредактировать свой ответ или, возможно, опубликуете ответ самостоятельно (с известными обходными путями, и, возможно, продолжайте обновлять его по мере того, как обсуждение LKML достигает более убедительных результатов.) Действительно впечатляюще видеть работу ядра ядра Linux! Fil
filbranden

Ответы:


1

Это именно то, для чего существует защита от трэша .

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


-3

Вы только выделяете память - вы на самом деле ничего не вкладываете в нее. «Нормальная» программа выделяет блок и затем начинает его использовать. Распределение не совпадает с использованием памяти.


3
Добро пожаловать на публикацию в Unix StackExchange. Он помещает в него данные, эти данные просто равны нулю. Смотрите memset (). Ядро Linux предоставляет физическую страницу оперативной памяти, как только вы пишете на виртуальную страницу; он не смотрит на конкретное значение, которое написано.
sourcejedi

На самом деле, я скомпилировал и запустил это на своем рабочем столе, начиная с 2 ГБ, свободно 6 ГБ. Первоначально он действительно менялся медленными темпами, и только когда он достигал предела, он активно менялся, что приводило к зависанию различных действий графического интерфейса.
Джереми Боден
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.