Когда моя система 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: Я подал ошибку с помощью средства отслеживания ошибок ядра. Кажется, это привлекает внимание, так что ... пальцы скрещены ...
источник
vmstat 1>somefile
непосредственно с системы, а затем посмотреть, что она сообщает после того, как система вернется к жизни. Я попробую это.swappiness
по умолчанию 60 (не то, чтобы изменение дало лучший результат). Ядро, используемое вvmstat
прогоне: 4.14.35, но я пробовал 4.15, 4.16 и даже вернулся к серии 4.0 (!): Всегда одинаковое поведение. И дело не в том, что я использую какой-то странный дистрибутив, это просто debian. Я не использую образы ядра из Debian (не то, что у меня есть необычные конфиги), но я попробовал одно из тех же ... поведения.Ответы:
Это именно то, для чего существует защита от трэша .
Он постоянно следит за состоянием подкачки и, когда что-то случайно начинает занимать большой объем ОЗУ, временно замораживает жадные до памяти процессы, поэтому у ядра есть время для замены некоторой памяти, при этом вся система не отвечает.
источник
Вы только выделяете память - вы на самом деле ничего не вкладываете в нее. «Нормальная» программа выделяет блок и затем начинает его использовать. Распределение не совпадает с использованием памяти.
источник